mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-09 19:40:19 +00:00
Add typescript support and automatic openapi client generation from ninja
This commit is contained in:
@ -7,7 +7,7 @@ from django.contrib.staticfiles.management.commands.collectstatic import (
|
||||
)
|
||||
|
||||
from staticfiles.apps import GENERATED_ROOT, IGNORE_PATTERNS_SCSS
|
||||
from staticfiles.processors import Scss, Webpack
|
||||
from staticfiles.processors import OpenApi, Scss, Webpack
|
||||
|
||||
|
||||
class Command(CollectStatic):
|
||||
@ -50,6 +50,7 @@ class Command(CollectStatic):
|
||||
return Path(location)
|
||||
|
||||
Scss.compile(self.collect_scss())
|
||||
OpenApi.compile() # This needs to be prior to webpack
|
||||
Webpack.compile()
|
||||
|
||||
collected = super().collect()
|
||||
|
@ -6,13 +6,15 @@ from django.contrib.staticfiles.management.commands.runserver import (
|
||||
)
|
||||
from django.utils.autoreload import DJANGO_AUTORELOAD_ENV
|
||||
|
||||
from staticfiles.processors import Webpack
|
||||
from staticfiles.processors import OpenApi, Webpack
|
||||
|
||||
|
||||
class Command(Runserver):
|
||||
"""Light wrapper around the statics runserver that integrates webpack auto bundling"""
|
||||
|
||||
def run(self, **options):
|
||||
# OpenApi generation needs to be before webpack
|
||||
OpenApi.compile()
|
||||
# Only run webpack server when debug is enabled
|
||||
# Also protects from re-launching the server if django reloads it
|
||||
if os.environ.get(DJANGO_AUTORELOAD_ENV) is None and settings.DEBUG:
|
||||
|
@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
from hashlib import sha1
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
@ -8,6 +9,7 @@ import rjsmin
|
||||
import sass
|
||||
from django.conf import settings
|
||||
|
||||
from sith.urls import api
|
||||
from staticfiles.apps import GENERATED_ROOT
|
||||
|
||||
|
||||
@ -71,3 +73,38 @@ class JS:
|
||||
minified = rjsmin.jsmin(p.read_text())
|
||||
p.write_text(minified)
|
||||
logging.getLogger("main").info(f"Minified {path}")
|
||||
|
||||
|
||||
class OpenApi:
|
||||
OPENAPI_DIR = GENERATED_ROOT / "openapi"
|
||||
|
||||
@classmethod
|
||||
def compile(cls):
|
||||
"""Compile a typescript client for the sith API. Only generates it if it changed"""
|
||||
logging.getLogger("django").info("Compiling open api typescript client")
|
||||
out = cls.OPENAPI_DIR / "schema.json"
|
||||
cls.OPENAPI_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
old_hash = ""
|
||||
if out.exists():
|
||||
with open(out, "rb") as f:
|
||||
old_hash = sha1(f.read()).hexdigest()
|
||||
|
||||
schema = api.get_openapi_schema()
|
||||
# Remove hash from operationIds
|
||||
# This is done for cache invalidation but this is too aggressive
|
||||
for path in schema["paths"].values():
|
||||
for action, desc in path.items():
|
||||
path[action]["operationId"] = "_".join(
|
||||
desc["operationId"].split("_")[:-1]
|
||||
)
|
||||
schema = str(schema)
|
||||
|
||||
if old_hash == sha1(schema.encode("utf-8")).hexdigest():
|
||||
logging.getLogger("django").info("✨ Api did not change, nothing to do ✨")
|
||||
return
|
||||
|
||||
with open(out, "w") as f:
|
||||
_ = f.write(schema)
|
||||
|
||||
subprocess.run(["npx", "openapi-ts"]).check_returncode()
|
||||
|
@ -12,7 +12,7 @@ from staticfiles.processors import JS, Scss
|
||||
|
||||
class ManifestPostProcessingStorage(ManifestStaticFilesStorage):
|
||||
def url(self, name: str, *, force: bool = False) -> str:
|
||||
"""Get the URL for a file, convert .scss calls to .css ones"""
|
||||
"""Get the URL for a file, convert .scss calls to .css ones and .ts to .js"""
|
||||
# This name swap has to be done here
|
||||
# Otherwise, the manifest isn't aware of the file and can't work properly
|
||||
path = Path(name)
|
||||
@ -27,6 +27,9 @@ class ManifestPostProcessingStorage(ManifestStaticFilesStorage):
|
||||
)
|
||||
name = str(path.with_suffix(".css"))
|
||||
|
||||
if path.suffix == ".ts":
|
||||
name = str(path.with_suffix(".js"))
|
||||
|
||||
return super().url(name, force=force)
|
||||
|
||||
def post_process(
|
||||
|
Reference in New Issue
Block a user