From aceae9aa1e29f683ffa888eb097355cf6b5e5a0b Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Mon, 2 Sep 2024 17:40:23 +0200 Subject: [PATCH] API: types schema improve typescript performance --- pkgs/clan-cli/api.py | 5 +- pkgs/clan-cli/clan_cli/api/__init__.py | 12 +++ pkgs/clan-cli/clan_cli/api/util.py | 2 +- pkgs/clan-cli/flake-module.nix | 24 ++++- pkgs/webview-ui/app/mock.ts | 27 ----- pkgs/webview-ui/app/package-lock.json | 135 ------------------------- pkgs/webview-ui/app/package.json | 2 - pkgs/webview-ui/app/src/api.ts | 6 +- pkgs/webview-ui/flake-module.nix | 5 +- 9 files changed, 38 insertions(+), 180 deletions(-) delete mode 100644 pkgs/webview-ui/app/mock.ts diff --git a/pkgs/clan-cli/api.py b/pkgs/clan-cli/api.py index a859137b7..f0ed535d0 100644 --- a/pkgs/clan-cli/api.py +++ b/pkgs/clan-cli/api.py @@ -7,10 +7,7 @@ from clan_cli.api import API def main() -> None: schema = API.to_json_schema() - print( - f"""export const schema = {json.dumps(schema, indent=2)} as const; -""" - ) + print(f"""{json.dumps(schema, indent=2)}""") if __name__ == "__main__": diff --git a/pkgs/clan-cli/clan_cli/api/__init__.py b/pkgs/clan-cli/clan_cli/api/__init__.py index 64a4a376f..b391803c3 100644 --- a/pkgs/clan-cli/clan_cli/api/__init__.py +++ b/pkgs/clan-cli/clan_cli/api/__init__.py @@ -163,6 +163,7 @@ API.register(open_file) "properties": {}, } + err_type = None for name, func in self._registry.items(): hints = get_type_hints(func) @@ -175,6 +176,15 @@ API.register(open_file) return_type = serialized_hints.pop("return") + if err_type is None: + err_type = next( + t + for t in return_type["oneOf"] + if ("error" in t["properties"]["status"]["enum"]) + ) + + return_type["oneOf"][1] = {"$ref": "#/$defs/error"} + sig = signature(func) required_args = [] for n, param in sig.parameters.items(): @@ -196,6 +206,8 @@ API.register(open_file) }, } + api_schema["$defs"] = {"error": err_type} + return api_schema def get_method_argtype(self, method_name: str, arg_name: str) -> Any: diff --git a/pkgs/clan-cli/clan_cli/api/util.py b/pkgs/clan-cli/clan_cli/api/util.py index 89901bb8d..45c762a22 100644 --- a/pkgs/clan-cli/clan_cli/api/util.py +++ b/pkgs/clan-cli/clan_cli/api/util.py @@ -92,7 +92,7 @@ def type_to_dict( required.add(pn) elif pv.get("oneOf") is not None: - if "null" not in [i["type"] for i in pv.get("oneOf", [])]: + if "null" not in [i.get("type") for i in pv.get("oneOf", [])]: required.add(pn) required_fields = { diff --git a/pkgs/clan-cli/flake-module.nix b/pkgs/clan-cli/flake-module.nix index deee72d8c..574179444 100644 --- a/pkgs/clan-cli/flake-module.nix +++ b/pkgs/clan-cli/flake-module.nix @@ -6,7 +6,11 @@ }: { perSystem = - { self', pkgs, ... }: + { + self', + pkgs, + ... + }: let flakeLock = lib.importJSON (self + /flake.lock); flakeInputs = builtins.removeAttrs inputs [ "self" ]; @@ -63,7 +67,6 @@ src = ./.; buildInputs = [ - # TODO: see postFixup clan-cli/default.nix:L188 pkgs.python3 self'.packages.clan-cli.propagatedBuildInputs @@ -84,17 +87,28 @@ buildInputs = [ pkgs.python3 - + self'.packages.json2ts # TODO: see postFixup clan-cli/default.nix:L188 self'.packages.clan-cli.propagatedBuildInputs ]; installPhase = '' ${self'.packages.classgen}/bin/classgen ${self'.packages.inventory-schema}/schema.json ./clan_cli/inventory/classes.py - - python api.py > $out + mkdir -p $out + python api.py > $out/API.json + ${self'.packages.json2ts}/bin/json2ts --input $out/API.json > $out/API.ts ''; }; + json2ts = pkgs.buildNpmPackage { + name = "json2ts"; + src = pkgs.fetchFromGitHub { + owner = "bcherny"; + repo = "json-schema-to-typescript"; + rev = "118d6a8e7a5a9397d1d390ce297f127ae674a623"; + hash = "sha256-ldAFfw3E0A0lIJyDSsshgPRPR7OmV/FncPsDhC3waT8="; + }; + npmDepsHash = "sha256-kLKau4SBxI9bMAd7X8/FQfCza2sYl/+0bg2LQcOQIJo="; + }; default = self'.packages.clan-cli; }; diff --git a/pkgs/webview-ui/app/mock.ts b/pkgs/webview-ui/app/mock.ts deleted file mode 100644 index bc4da6259..000000000 --- a/pkgs/webview-ui/app/mock.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { JSONSchemaFaker } from "json-schema-faker"; -import { schema } from "./api/index"; -import { OperationNames } from "./src/api"; - -const faker = JSONSchemaFaker; - -faker.option({ - alwaysFakeOptionals: true, - useExamplesValue: true, -}); - -const getFakeResponse = (method: OperationNames, data: any) => { - const fakeData = faker.generate(schema.properties[method].properties.return); - const { op_key } = data; - if (method === "open_file") { - return { - status: "success", - data: "/home/johannes/git/clan-core", - op_key, - }; - } - - // @ts-expect-error: fakeData is guaranteed to always be some object - return { ...fakeData, op_key }; -}; - -export { getFakeResponse }; diff --git a/pkgs/webview-ui/app/package-lock.json b/pkgs/webview-ui/app/package-lock.json index 317efb017..49a67be6b 100644 --- a/pkgs/webview-ui/app/package-lock.json +++ b/pkgs/webview-ui/app/package-lock.json @@ -31,8 +31,6 @@ "eslint": "^8.57.0", "eslint-plugin-tailwindcss": "^3.17.0", "jsdom": "^24.1.0", - "json-schema-faker": "^0.5.6", - "json-schema-to-ts": "^3.1.0", "postcss": "^8.4.38", "postcss-url": "^10.1.3", "prettier": "^3.2.5", @@ -357,18 +355,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", - "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.24.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", @@ -2370,12 +2356,6 @@ "node": ">=8" } }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", - "dev": true - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3118,19 +3098,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", @@ -3341,12 +3308,6 @@ "node": ">= 6" } }, - "node_modules/format-util": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", - "integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==", - "dev": true - }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -3850,66 +3811,6 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, - "node_modules/json-schema-faker": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.6.tgz", - "integrity": "sha512-u/cFC26/GDxh2vPiAC8B8xVvpXAW+QYtG2mijEbKrimCk8IHtiwQBjCE8TwvowdhALWq9IcdIWZ+/8ocXvdL3Q==", - "dev": true, - "dependencies": { - "json-schema-ref-parser": "^6.1.0", - "jsonpath-plus": "^7.2.0" - }, - "bin": { - "jsf": "bin/gen.cjs" - } - }, - "node_modules/json-schema-ref-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", - "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", - "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", - "dev": true, - "dependencies": { - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.12.1", - "ono": "^4.0.11" - } - }, - "node_modules/json-schema-ref-parser/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/json-schema-ref-parser/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-to-ts": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.0.tgz", - "integrity": "sha512-UeVN/ery4/JeXI8h4rM8yZPxsH+KqPi/84qFxHfTGHZnWnK9D0UU9ZGYO+6XAaJLqCWMiks+ARuFOKAiSxJCHA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.18.3", - "ts-algebra": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3932,15 +3833,6 @@ "node": ">=6" } }, - "node_modules/jsonpath-plus": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.2.0.tgz", - "integrity": "sha512-zBfiUPM5nD0YZSBT/o/fbCUlCcepMIdP0CJZxM1+KgA4f2T206f6VAg9e7mX35+KlMaIc5qXW34f3BnwJ3w+RA==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4397,15 +4289,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ono": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz", - "integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==", - "dev": true, - "dependencies": { - "format-util": "^1.0.3" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -4965,12 +4848,6 @@ "node": ">=8.10.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -5325,12 +5202,6 @@ "node": ">=0.10.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -5750,12 +5621,6 @@ "node": ">=18" } }, - "node_modules/ts-algebra": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", - "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", - "dev": true - }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", diff --git a/pkgs/webview-ui/app/package.json b/pkgs/webview-ui/app/package.json index 8681e2830..1cd02ed29 100644 --- a/pkgs/webview-ui/app/package.json +++ b/pkgs/webview-ui/app/package.json @@ -24,8 +24,6 @@ "eslint": "^8.57.0", "eslint-plugin-tailwindcss": "^3.17.0", "jsdom": "^24.1.0", - "json-schema-faker": "^0.5.6", - "json-schema-to-ts": "^3.1.0", "postcss": "^8.4.38", "postcss-url": "^10.1.3", "prettier": "^3.2.5", diff --git a/pkgs/webview-ui/app/src/api.ts b/pkgs/webview-ui/app/src/api.ts index b7d48bcd9..6fcb9ee4b 100644 --- a/pkgs/webview-ui/app/src/api.ts +++ b/pkgs/webview-ui/app/src/api.ts @@ -1,9 +1,7 @@ -import { FromSchema } from "json-schema-to-ts"; -import { schema } from "@/api"; +import schema from "@/api/API.json" assert { type: "json" }; +import { API } from "@/api/API"; import { nanoid } from "nanoid"; -export type API = FromSchema; - export type OperationNames = keyof API; export type OperationArgs = API[T]["arguments"]; export type OperationResponse = API[T]["return"]; diff --git a/pkgs/webview-ui/flake-module.nix b/pkgs/webview-ui/flake-module.nix index a35461625..6791f5304 100644 --- a/pkgs/webview-ui/flake-module.nix +++ b/pkgs/webview-ui/flake-module.nix @@ -19,7 +19,7 @@ preBuild = '' mkdir -p api - cat ${config.packages.clan-ts-api} > api/index.ts + cp -r ${config.packages.clan-ts-api}/* api ''; }; devShells.webview-ui = pkgs.mkShell { @@ -50,7 +50,8 @@ mkdir -p ./app/api - cat ${config.packages.clan-ts-api} > ./app/api/index.ts + cp -r ${config.packages.clan-ts-api}/* app/api + chmod -R +w app/api ''; }; };