From 6e557fe2a10cc1cb649a175f8bad3c2e47d5e2ba Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Tue, 19 Mar 2024 07:47:14 -0700 Subject: [PATCH 01/80] standardise json formatting --- .gitignore | 1 - .prettierignore | 1 + .vscode/launch.json | 76 +++++++++++----------- .vscode/settings.json | 60 +++++++++++------- .vscode/tasks.json | 26 ++++---- tslint.json | 143 ++++++++++++++++++------------------------ 6 files changed, 148 insertions(+), 159 deletions(-) create mode 100644 .prettierignore diff --git a/.gitignore b/.gitignore index f800a1642..7178f4122 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,3 @@ test/fixtures/objective-c/quicktype /.bsp .metals .scala-build -.vscode diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..c4dbe99c9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +test/inputs/* diff --git a/.vscode/launch.json b/.vscode/launch.json index 7c36e6c8a..1cbad2c56 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,40 +1,40 @@ { - // Use IntelliSense to learn about possible Node.js debug attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "quicktype", - "type": "node", - "request": "launch", - "program": "${workspaceRoot}/node_modules/ts-node/dist/_bin.js", - "runtimeArgs": ["--nolazy"], - "args": [ - "--project", - "src/cli/tsconfig.json", - "src/cli/index.ts", - "--lang", - "dart", - "--src-lang", - "json", - "./test/inputs/json/priority/blns-object.json" - ], - "cwd": "${workspaceRoot}", - "protocol": "inspector" - }, - { - "name": "test", - "type": "node", - "request": "launch", - "program": "${workspaceRoot}/node_modules/ts-node/dist/_bin.js", - "args": ["--project", "test/tsconfig.json", "test/test.ts"], - "cwd": "${workspaceRoot}", - "protocol": "inspector", - "env": { - "CPUs": "1", - "FIXTURE": "golang" - } - } - ] + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "quicktype", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/ts-node/dist/_bin.js", + "runtimeArgs": ["--nolazy"], + "args": [ + "--project", + "src/cli/tsconfig.json", + "src/cli/index.ts", + "--lang", + "dart", + "--src-lang", + "json", + "./test/inputs/json/priority/blns-object.json" + ], + "cwd": "${workspaceRoot}", + "protocol": "inspector" + }, + { + "name": "test", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/ts-node/dist/_bin.js", + "args": ["--project", "test/tsconfig.json", "test/test.ts"], + "cwd": "${workspaceRoot}", + "protocol": "inspector", + "env": { + "CPUs": "1", + "FIXTURE": "golang" + } + } + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index ea68a90d3..f872151c0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,25 +1,37 @@ { - // Place your settings in this file to overwrite default and user settings. - "editor.formatOnSave": true, - "spellright.ignoreFiles": [ - "**/.gitignore", - "**/.spellignore" - ], - "search.exclude": { - "**/.git": true, - "**/node_modules": true, - "**/bower_components": true, - "**/tmp": true, - "output": true, - "**/obj": true, - "**/bin": true, - "test/inputs": true, - "test/runs": true, - "app/build": true, - "elm-stuff": true, - "dist": true - }, - "explorer.excludeGitIgnore": false, - "spellright.documentTypes": [], - "java.configuration.updateBuildConfiguration": "automatic" -} \ No newline at end of file + // Place your settings in this file to overwrite default and user settings. + "editor.formatOnSave": true, + "spellright.ignoreFiles": ["**/.gitignore", "**/.spellignore"], + "search.exclude": { + "**/.git": true, + "**/node_modules": true, + "**/bower_components": true, + "**/tmp": true, + "output": true, + "**/obj": true, + "**/bin": true, + "test/inputs": true, + "test/runs": true, + "app/build": true, + "elm-stuff": true, + "dist": true + }, + "explorer.excludeGitIgnore": false, + "spellright.documentTypes": [], + "java.configuration.updateBuildConfiguration": "automatic", + + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.wordWrap": "on", + "editor.insertSpaces": true, + "editor.tabSize": 4, + "editor.detectIndentation": false + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.wordWrap": "on", + "editor.insertSpaces": true, + "editor.tabSize": 4, + "editor.detectIndentation": false + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d41fa1af8..f36e83f3d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,15 +1,13 @@ { - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "tslint", - "group": "build", - "problemMatcher": [ - "$tslint5" - ] - } - ] -} \ No newline at end of file + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "tslint", + "group": "build", + "problemMatcher": ["$tslint5"] + } + ] +} diff --git a/tslint.json b/tslint.json index 6bfd49e76..ac74002e7 100644 --- a/tslint.json +++ b/tslint.json @@ -1,88 +1,67 @@ { - "rules": { - "await-promise": true, - "promise-function-async": true, - "no-floating-promises": true, - "align": [true, "parameters", "statements"], - "ban": false, - "class-name": true, - "comment-format": [true, "check-space"], - "curly": false, - "eofline": false, - "forin": true, - "indent": [true, "spaces", 4], - "interface-name": [true, "never-prefix"], - "jsdoc-format": true, - "jsx-no-lambda": false, - "jsx-no-multiline-js": false, - "label-position": true, - "max-line-length": false, - "member-ordering": [true, "static-before-instance"], + "rules": { + "await-promise": true, + "promise-function-async": true, + "no-floating-promises": true, + "align": [true, "parameters", "statements"], + "ban": false, + "class-name": true, + "comment-format": [true, "check-space"], + "curly": false, + "eofline": false, + "forin": true, + "indent": [true, "spaces", 4], + "interface-name": [true, "never-prefix"], + "jsdoc-format": true, + "jsx-no-lambda": false, + "jsx-no-multiline-js": false, + "label-position": true, + "max-line-length": false, + "member-ordering": [true, "static-before-instance"], - "no-any": false, + "no-any": false, - "no-arg": true, - "no-bitwise": false, - "no-console": [ - false, - "log", - "error", - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-consecutive-blank-lines": true, - "no-construct": true, - "no-debugger": true, - "no-duplicate-variable": true, - "no-empty": [true, "allow-empty-catch"], - "no-eval": true, - "no-shadowed-variable": true, - "no-string-literal": false, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": false, - "no-unsafe-any": false, - "no-unused-expression": true, - "no-use-before-declare": false, - "no-unused-variable": true, - "no-var-keyword": true, - "no-void-expression": false, - "strict-boolean-expressions": true, - "one-line": [ - true, - "check-catch", - "check-else", - "check-open-brace", - "check-whitespace" - ], - "quotemark": [true, "double", "avoid-escape"], - "radix": true, - "semicolon": [true, "always", "ignore-bound-class-methods"], - "switch-default": true, + "no-arg": true, + "no-bitwise": false, + "no-console": [false, "log", "error", "debug", "info", "time", "timeEnd", "trace"], + "no-consecutive-blank-lines": true, + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": [true, "allow-empty-catch"], + "no-eval": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": false, + "no-unsafe-any": false, + "no-unused-expression": true, + "no-use-before-declare": false, + "no-unused-variable": true, + "no-var-keyword": true, + "no-void-expression": false, + "strict-boolean-expressions": true, + "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], + "quotemark": [true, "double", "avoid-escape"], + "radix": true, + "semicolon": [true, "always", "ignore-bound-class-methods"], + "switch-default": true, - "trailing-comma": false, + "trailing-comma": false, - "triple-equals": [true, "allow-null-check"], - "typedef": [true, "parameter", "property-declaration"], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "variable-name": [ - true, - "ban-keywords", - "check-format", - "allow-leading-underscore", - "allow-pascal-case" - ], - "whitespace": [false] - } + "triple-equals": [true, "allow-null-check"], + "typedef": [true, "parameter", "property-declaration"], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], + "whitespace": [false] + } } From a7cec76f8e208ac15f363c221ffa8acca697a657 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Tue, 19 Mar 2024 07:47:14 -0700 Subject: [PATCH 02/80] add file association for schema files --- .vscode/settings.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f872151c0..f57596256 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,6 @@ { // Place your settings in this file to overwrite default and user settings. "editor.formatOnSave": true, - "spellright.ignoreFiles": ["**/.gitignore", "**/.spellignore"], "search.exclude": { "**/.git": true, "**/node_modules": true, @@ -17,9 +16,12 @@ "dist": true }, "explorer.excludeGitIgnore": false, - "spellright.documentTypes": [], "java.configuration.updateBuildConfiguration": "automatic", + "files.associations": { + "*.schema": "jsonc" + }, + "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.wordWrap": "on", From b2a79041e6bbca0c08152f329f790fa6f2b08230 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 7 Apr 2024 08:50:57 -0700 Subject: [PATCH 03/80] install eslint packages --- package-lock.json | 15983 +++++++++++++++++++++++++++++++++++++------- package.json | 13 +- 2 files changed, 13688 insertions(+), 2308 deletions(-) diff --git a/package-lock.json b/package-lock.json index 06154c3d6..a0ff1b196 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ ], "dependencies": { "@glideapps/ts-necessities": "^2.1.3", - "@types/readable-stream": "^4.0.10", "chalk": "^4.1.2", "collection-utils": "^1.0.1", "command-line-args": "^5.2.1", @@ -45,8 +44,18 @@ "@types/shelljs": "^0.8.12", "@types/stream-json": "^1.7.3", "@types/urijs": "^1.19.25", + "@typescript-eslint/eslint-plugin": "^6.3.0", + "@typescript-eslint/parser": "^6.3.0", "ajv": "^5.5.2", "deep-equal": "^2.2.2", + "eslint": "^8.57.0", + "eslint-config-canonical": "^41.1.7", + "eslint-config-prettier": "^6.10.0", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-canonical": "^3.4.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-json": "^3.1.0", + "eslint-plugin-prettier": "^4.2.1", "exit": "^0.1.2", "prettier": "^3.0.1", "promise-timeout": "^1.3.0", @@ -80,865 +89,931 @@ "node": ">=12.17" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/@glideapps/ts-necessities": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.1.3.tgz", - "integrity": "sha512-q9U8v/n9qbkd2zDYjuX3qtlbl+OIyI9zF+zQhZjfYOE9VMDH7tfcUSJ9p0lXoY3lxmGFne09yi4iiNeQUwV7AA==" - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, "engines": { "node": ">=6.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mark.probst/typescript-json-schema": { - "version": "0.55.0", - "resolved": "https://registry.npmjs.org/@mark.probst/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", - "integrity": "sha512-jI48mSnRgFQxXiE/UTUCVCpX8lK3wCFKLF1Ss2aEreboKNuLQGt3e0/YFqWVHe/WENxOaqiJvwOz+L/SrN2+qQ==", + "node_modules/@ardatan/sync-fetch": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@ardatan/sync-fetch/-/sync-fetch-0.0.1.tgz", + "integrity": "sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA==", + "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/node": "^16.9.2", - "glob": "^7.1.7", - "path-equal": "^1.1.2", - "safe-stable-stringify": "^2.2.0", - "ts-node": "^10.9.1", - "typescript": "4.9.4", - "yargs": "^17.1.1" + "node-fetch": "^2.6.1" }, - "bin": { - "typescript-json-schema": "bin/typescript-json-schema" + "engines": { + "node": ">=14" } }, - "node_modules/@mark.probst/typescript-json-schema/node_modules/@types/node": { - "version": "16.18.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", - "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==" - }, - "node_modules/@mark.probst/typescript-json-schema/node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { - "node": ">=4.2.0" + "node": ">=6.9.0" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" - }, - "node_modules/@tsconfig/node18": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-1.0.1.tgz", - "integrity": "sha512-sNFeK6X2ATlhlvzyH4kKYQlfHXE2f2/wxtB9ClvYXevWpmwkUT7VaSrjIN9E76Qebz8qP5JOJJ9jD3QoD/Z9TA==", - "dev": true - }, - "node_modules/@types/browser-or-node": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/browser-or-node/-/browser-or-node-1.3.2.tgz", - "integrity": "sha512-CkvJrvVMI4ZHbiL+Df22Owzq1IYnHnoSrM8s6Dmy4MRdqvdFi9bHsIvyFrSGJPOxvFI9Y3MqY2gFCqIafJBcfw==", - "dev": true - }, - "node_modules/@types/command-line-args": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz", - "integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==", - "dev": true - }, - "node_modules/@types/command-line-usage": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", - "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==", - "dev": true + "node_modules/@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "node_modules/@babel/core": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", + "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", "dev": true, "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@types/graphql": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.11.8.tgz", - "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", - "dev": true + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/@types/js-base64": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/js-base64/-/js-base64-3.3.1.tgz", - "integrity": "sha512-Zw33oQNAvDdAN9b0IE5stH0y2MylYvtU7VVTKEJPxhyM2q57CVaNJhtJW258ah24NRtaiA23tptUmVn3dmTKpw==", - "deprecated": "This is a stub types definition. js-base64 provides its own type definitions, so you do not need this installed.", + "node_modules/@babel/eslint-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz", + "integrity": "sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==", "dev": true, "dependencies": { - "js-base64": "*" + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" - }, - "node_modules/@types/lodash": { - "version": "4.14.197", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", - "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", - "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==" + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } }, - "node_modules/@types/pako": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.0.tgz", - "integrity": "sha1-6q6DZNG391LiY7w/1o3+yY5hNsU=", - "dev": true + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/@types/pluralize": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.30.tgz", - "integrity": "sha512-kVww6xZrW/db5BR9OqiT71J9huRdQ+z/r+LbDuT7/EK50mCmj5FoaIARnVv0rvjUS/YpDox0cDU9lpQT011VBA==", - "dev": true + "node_modules/@babel/eslint-plugin": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.23.5.tgz", + "integrity": "sha512-03+E/58Hoo/ui69gR+beFdGpplpoVK0BSIdke2iw4/Bz7eGN0ssRenNlnU4nmbkowNQOPCStKSwFr8H6DiY49g==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/eslint-parser": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } }, - "node_modules/@types/readable-stream": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", - "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", + "node_modules/@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dev": true, "dependencies": { - "@types/node": "*", - "safe-buffer": "~5.1.1" + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } }, - "node_modules/@types/shelljs": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.12.tgz", - "integrity": "sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, + "peer": true, "dependencies": { - "@types/glob": "~7.2.0", - "@types/node": "*" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/stream-chain": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stream-chain/-/stream-chain-2.0.1.tgz", - "integrity": "sha512-D+Id9XpcBpampptkegH7WMsEk6fUdf9LlCIX7UhLydILsqDin4L0QT7ryJR0oycwC7OqohIzdfcMHVZ34ezNGg==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@types/node": "*" + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/stream-json": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@types/stream-json/-/stream-json-1.7.3.tgz", - "integrity": "sha512-Jqsyq5VPOTWorvEmzWhEWH5tJnHA+bB8vt/Zzb11vSDj8esfSHDMj2rbVjP0mfJQzl3YBJSXBBq08iiyaBK3KA==", + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "dependencies": { - "@types/node": "*", - "@types/stream-chain": "*" + "yallist": "^3.0.2" } }, - "node_modules/@types/unicode-properties": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/unicode-properties/-/unicode-properties-1.3.0.tgz", - "integrity": "sha512-kDVlxpdkCfgvzfXcglkr7j4OSMjCEEo/Jloj4tFuldYZpQ9Uypy7FGXPhNstoj4eGvhddwuu5n0EfI+XdWVoVA==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, - "node_modules/@types/urijs": { - "version": "1.19.25", - "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", - "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==" + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@types/yaml": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", - "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==", - "deprecated": "This is a stub types definition. yaml provides its own type definitions, so you do not need this installed.", + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "yaml": "*" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, "dependencies": { - "event-target-shim": "^5.0.0" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">=6.5" + "node": ">=6.9.0" } }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=6.9.0" } }, - "node_modules/ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "sprintf-js": "~1.0.2" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, "engines": { - "node": ">=6" + "node": ">=6.9.0" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6.9.0" } }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/browser-or-node": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", - "integrity": "sha512-sVIA0cysIED0nbmNOm7sZzKfgN1rpFmrqvLZaFWspaBAftfQcezlC81G6j6U2RJf4Lh66zFxrCeOsvkUXIcPWg==" + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", + "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", "dev": true, + "peer": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "@babel/helper-plugin-utils": "^7.24.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chalk-template": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", - "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dev": true, + "peer": true, "dependencies": { - "chalk": "^4.1.2" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/chalk-template?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dev": true, + "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@babel/runtime": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", + "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" + "regenerator-runtime": "^0.14.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.9.0" } }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@babel/runtime-corejs3": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.1.tgz", + "integrity": "sha512-T9ko/35G+Bkl+win48GduaPlhSlOjjE5s1TeiEcD+QpxlLQnoEfb/nO/T+TQqkm+ipFwORn+rB8w14iJ/uD0bg==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=4" } }, - "node_modules/collection-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", - "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==" - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/color-convert/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=4.0.0" + "node": ">=12" } }, - "node_modules/command-line-usage": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", - "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, "dependencies": { - "array-back": "^6.2.2", - "chalk-template": "^0.4.0", - "table-layout": "^3.0.0", - "typical": "^7.1.1" + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { - "node": ">=12.20.0" + "node": ">=16" } }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=12.17" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", - "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, "engines": { - "node": ">=12.17" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, "dependencies": { - "node-fetch": "^2.6.12" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/deep-equal": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", - "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.1", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "node_modules/@eslint/eslintrc/node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, "engines": { - "node": ">=0.3.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "node_modules/@glideapps/ts-necessities": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.1.3.tgz", + "integrity": "sha512-q9U8v/n9qbkd2zDYjuX3qtlbl+OIyI9zF+zQhZjfYOE9VMDH7tfcUSJ9p0lXoY3lxmGFne09yi4iiNeQUwV7AA==" }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "node_modules/@graphql-eslint/eslint-plugin": { + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@graphql-eslint/eslint-plugin/-/eslint-plugin-3.20.1.tgz", + "integrity": "sha512-RbwVlz1gcYG62sECR1u0XqMh8w5e5XMCCZoMvPQ3nJzEBCTfXLGX727GBoRmSvY1x4gJmqNZ1lsOX7lZY14RIw==", + "dev": true, "dependencies": { - "iconv-lite": "^0.6.2" + "@babel/code-frame": "^7.18.6", + "@graphql-tools/code-file-loader": "^7.3.6", + "@graphql-tools/graphql-tag-pluck": "^7.3.6", + "@graphql-tools/utils": "^9.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "fast-glob": "^3.2.12", + "graphql-config": "^4.4.0", + "graphql-depth-limit": "^1.1.0", + "lodash.lowercase": "^4.3.0", + "tslib": "^2.4.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "node_modules/@graphql-eslint/eslint-plugin/node_modules/@graphql-tools/code-file-loader": { + "version": "7.3.23", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-7.3.23.tgz", + "integrity": "sha512-8Wt1rTtyTEs0p47uzsPJ1vAtfAx0jmxPifiNdmo9EOCuUPyQGEbMaik/YkqZ7QUFIEYEQu+Vgfo8tElwOPtx5Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" + "@graphql-tools/graphql-tag-pluck": "7.5.2", + "@graphql-tools/utils": "^9.2.1", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/@graphql-eslint/eslint-plugin/node_modules/@graphql-tools/graphql-tag-pluck": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-7.5.2.tgz", + "integrity": "sha512-RW+H8FqOOLQw0BPXaahYepVSRjuOHw+7IL8Opaa5G5uYGOBxoXR7DceyQ7BcpMgktAOOmpDNQ2WtcboChOJSRA==", "dev": true, - "engines": { - "node": ">=0.8.0" + "dependencies": { + "@babel/parser": "^7.16.8", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "node_modules/@graphql-eslint/eslint-plugin/node_modules/@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } + "node_modules/@graphql-eslint/eslint-plugin/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "dev": true, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/exec-sh": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz", - "integrity": "sha512-aLt95pexaugVtQerpmE51+4QfWrNc304uez7jvj6fWnN8GeEHpttB8F36n8N7uVhUMbH/1enbxQ9HImZ4w/9qg==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "merge": "^1.1.3" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "engines": { - "node": ">= 0.8.0" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, "dependencies": { - "array-back": "^3.0.1" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.0.0" } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "is-callable": "^1.1.3" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=6.0.0" } }, - "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@mark.probst/typescript-json-schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@mark.probst/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", + "integrity": "sha512-jI48mSnRgFQxXiE/UTUCVCpX8lK3wCFKLF1Ss2aEreboKNuLQGt3e0/YFqWVHe/WENxOaqiJvwOz+L/SrN2+qQ==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/node": "^16.9.2", + "glob": "^7.1.7", + "path-equal": "^1.1.2", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "yargs": "^17.1.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "typescript-json-schema": "bin/typescript-json-schema" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/@mark.probst/typescript-json-schema/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==" + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@next/eslint-plugin-next": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.6.tgz", + "integrity": "sha512-ng7pU/DDsxPgT6ZPvuprxrkeew3XaRf4LAT4FabaEO/hAbvVx4P7wqnqdbTdDn1kgTvsI4tpIgT4Awn/m0bGbg==", + "dev": true, + "dependencies": { + "glob": "7.1.7" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -949,754 +1024,877 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graphql": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.11.7.tgz", - "integrity": "sha512-x7uDjyz8Jx+QPbpCFCMQ8lltnQa4p4vSYHx6ADe8rVYRTdsyhCJbvSty5DAsLVmU6cGakl+r8HQYolKHxk/tiw==", - "dependencies": { - "iterall": "1.1.3" + "eslint-scope": "5.1.1" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { - "function-bind": "^1.1.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8.0.0" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, "engines": { - "node": ">=4" + "node": ">=4.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", + "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" } }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "node_modules/@peculiar/asn1-schema/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true }, - "node_modules/internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "tslib": "^2.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8.0.0" } }, - "node_modules/interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "node_modules/@peculiar/json-schema/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "node_modules/@peculiar/webcrypto": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", + "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.7.8" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10.12.0" } }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/@peculiar/webcrypto/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/unts" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/@repeaterjs/repeater": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz", + "integrity": "sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==", + "dev": true }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/@rushstack/eslint-patch": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz", + "integrity": "sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==", + "dev": true }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + }, + "node_modules/@tsconfig/node18": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-1.0.1.tgz", + "integrity": "sha512-sNFeK6X2ATlhlvzyH4kKYQlfHXE2f2/wxtB9ClvYXevWpmwkUT7VaSrjIN9E76Qebz8qP5JOJJ9jD3QoD/Z9TA==", + "dev": true + }, + "node_modules/@types/browser-or-node": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/browser-or-node/-/browser-or-node-1.3.2.tgz", + "integrity": "sha512-CkvJrvVMI4ZHbiL+Df22Owzq1IYnHnoSrM8s6Dmy4MRdqvdFi9bHsIvyFrSGJPOxvFI9Y3MqY2gFCqIafJBcfw==", + "dev": true + }, + "node_modules/@types/command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==", + "dev": true + }, + "node_modules/@types/command-line-usage": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", + "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" } }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "node_modules/@types/graphql": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.11.8.tgz", + "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", + "dev": true + }, + "node_modules/@types/js-base64": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/js-base64/-/js-base64-3.3.1.tgz", + "integrity": "sha512-Zw33oQNAvDdAN9b0IE5stH0y2MylYvtU7VVTKEJPxhyM2q57CVaNJhtJW258ah24NRtaiA23tptUmVn3dmTKpw==", + "deprecated": "This is a stub types definition. js-base64 provides its own type definitions, so you do not need this installed.", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "js-base64": "*" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.197", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", + "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", + "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/pako": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.0.tgz", + "integrity": "sha1-6q6DZNG391LiY7w/1o3+yY5hNsU=", + "dev": true + }, + "node_modules/@types/pluralize": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.30.tgz", + "integrity": "sha512-kVww6xZrW/db5BR9OqiT71J9huRdQ+z/r+LbDuT7/EK50mCmj5FoaIARnVv0rvjUS/YpDox0cDU9lpQT011VBA==", + "dev": true + }, + "node_modules/@types/readable-stream": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", + "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/node": "*", + "safe-buffer": "~5.1.1" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "node_modules/@types/shelljs": { + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.12.tgz", + "integrity": "sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/glob": "~7.2.0", + "@types/node": "*" } }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "node_modules/@types/stream-chain": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stream-chain/-/stream-chain-2.0.1.tgz", + "integrity": "sha512-D+Id9XpcBpampptkegH7WMsEk6fUdf9LlCIX7UhLydILsqDin4L0QT7ryJR0oycwC7OqohIzdfcMHVZ34ezNGg==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@types/node": "*" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "node_modules/@types/stream-json": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@types/stream-json/-/stream-json-1.7.3.tgz", + "integrity": "sha512-Jqsyq5VPOTWorvEmzWhEWH5tJnHA+bB8vt/Zzb11vSDj8esfSHDMj2rbVjP0mfJQzl3YBJSXBBq08iiyaBK3KA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/node": "*", + "@types/stream-chain": "*" } }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "engines": { - "node": ">=0.10.0" + "node_modules/@types/unicode-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/unicode-properties/-/unicode-properties-1.3.0.tgz", + "integrity": "sha512-kDVlxpdkCfgvzfXcglkr7j4OSMjCEEo/Jloj4tFuldYZpQ9Uypy7FGXPhNstoj4eGvhddwuu5n0EfI+XdWVoVA==", + "dev": true + }, + "node_modules/@types/urijs": { + "version": "1.19.25", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", + "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/@types/yaml": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", + "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==", + "deprecated": "This is a stub types definition. yaml provides its own type definitions, so you do not need this installed.", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "yaml": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": ">= 0.4" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", + "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "@typescript-eslint/utils": "5.62.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/iterall": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz", - "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==" - }, - "node_modules/js-base64": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", - "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==" - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/js-yaml/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==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.assignwith": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", - "integrity": "sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">=10" + "node": ">=8.0.0" } }, - "node_modules/make-error": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", - "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==" - }, - "node_modules/merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", - "dev": true + "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "tslib": "^1.8.1" }, "engines": { - "node": "*" + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "minimist": "^1.2.6" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "engines": { - "node": "*" + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, "dependencies": { - "whatwg-url": "^5.0.0" + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "4.x || >=6.0.0" + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "encoding": "^0.1.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { - "encoding": { + "typescript": { "optional": true } } }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": ">= 0.4" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">= 0.4" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" }, "engines": { - "node": ">= 0.4" + "node": "^16.0.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, "dependencies": { - "wrappy": "1" + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true }, - "node_modules/path-equal": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", - "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==" + "node_modules/@whatwg-node/events": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.0.3.tgz", + "integrity": "sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA==", + "dev": true }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" + "node_modules/@whatwg-node/fetch": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", + "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", + "dev": true, + "dependencies": { + "@peculiar/webcrypto": "^1.4.0", + "@whatwg-node/node-fetch": "^0.3.6", + "busboy": "^1.6.0", + "urlpattern-polyfill": "^8.0.0", + "web-streams-polyfill": "^3.2.1" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "node_modules/@whatwg-node/node-fetch": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.3.6.tgz", + "integrity": "sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA==", + "dev": true, + "dependencies": { + "@whatwg-node/events": "^0.0.3", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + } + }, + "node_modules/@whatwg-node/node-fetch/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, - "node_modules/pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, "engines": { - "node": ">=4" + "node": ">=6.5" } }, - "node_modules/prettier": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz", - "integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==", - "dev": true, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "bin": { - "prettier": "bin/prettier.cjs" + "acorn": "bin/acorn" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": ">=0.4.0" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/promise-timeout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/promise-timeout/-/promise-timeout-1.3.0.tgz", - "integrity": "sha512-5yANTE0tmi5++POym6OgtFmwfDvOXABD9oj/jLQr5GPEyuNEb7jH4wbbANJceJid49jwhi1RddxnhnEAb/doqg==", - "dev": true + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/quicktype-core": { - "resolved": "packages/quicktype-core", - "link": true + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } }, - "node_modules/quicktype-graphql-input": { - "resolved": "packages/quicktype-graphql-input", - "link": true + "node_modules/ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "dependencies": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } }, - "node_modules/quicktype-typescript-input": { - "resolved": "packages/quicktype-typescript-input", - "link": true + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } }, - "node_modules/readable-stream": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" + "color-convert": "^1.9.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "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": { - "safe-buffer": "~5.2.0" + "sprintf-js": "~1.0.2" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "dependencies": { - "resolve": "^1.1.6" - }, + "dequal": "^2.0.3" + } + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", "engines": { - "node": ">= 0.10" + "node": ">=6" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -1705,562 +1903,454 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "path-parse": "^1.0.5" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", - "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, "dependencies": { - "internal-slot": "^1.0.4" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stream-chain": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", - "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" - }, - "node_modules/stream-json": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.8.0.tgz", - "integrity": "sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==", + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, "dependencies": { - "stream-chain": "^2.2.5" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" } }, - "node_modules/stream-read-all": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz", - "integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==", - "engines": { - "node": ">=10" + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" } }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, "dependencies": { - "safe-buffer": "~5.1.0" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string-to-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-3.0.1.tgz", - "integrity": "sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg==", - "dependencies": { - "readable-stream": "^3.4.0" + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/string-to-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dev": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" }, "engines": { - "node": ">= 6" + "node": ">=12.0.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/asn1js/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "tslib": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/ast-types/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "possible-typed-array-names": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { "node": ">=4" } }, - "node_modules/table-layout": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz", - "integrity": "sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==", + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, "dependencies": { - "@75lb/deep-merge": "^1.1.1", - "array-back": "^6.2.2", - "command-line-args": "^5.2.1", - "command-line-usage": "^7.0.0", - "stream-read-all": "^3.0.1", - "typical": "^7.1.1", - "wordwrapjs": "^5.1.0" - }, - "bin": { - "table-layout": "bin/cli.js" - }, - "engines": { - "node": ">=12.17" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "engines": { - "node": ">=12.17" + "dequal": "^2.0.3" } }, - "node_modules/table-layout/node_modules/typical": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", - "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", - "engines": { - "node": ">=12.17" - } + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "node_modules/tiny-inflate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.2.tgz", - "integrity": "sha1-k9nez/yIBb1X6uQxDwt0Xptvs6c=" + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "dev": true }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "bin": { - "acorn": "bin/acorn" + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "node_modules/browser-or-node": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", + "integrity": "sha512-sVIA0cysIED0nbmNOm7sZzKfgN1rpFmrqvLZaFWspaBAftfQcezlC81G6j6U2RJf4Lh66zFxrCeOsvkUXIcPWg==" }, - "node_modules/tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { - "tslint": "bin/tslint" + "browserslist": "cli.js" }, "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/tslint/node_modules/@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "@babel/highlight": "^7.0.0" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "node_modules/tslint/node_modules/@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true, - "dependencies": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/tslint/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "streamsearch": "^1.1.0" }, "engines": { - "node": ">=4" + "node": ">=10.16.0" } }, - "node_modules/tslint/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/tslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/unicode-properties": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/unicode-properties/node_modules/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" - }, - "node_modules/unicode-properties/node_modules/unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/urijs": { - "version": "1.19.11", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "node_modules/watch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", - "integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=", + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { - "node": ">=0.1.95" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=6" } }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "node_modules/caniuse-lite": { + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - }, - "node_modules/wordwrapjs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", - "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", - "engines": { - "node": ">=12.17" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "chalk": "^4.1.2" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/chalk/chalk-template?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { + "node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -2274,7 +2364,7 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/color-convert": { + "node_modules/chalk/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -2285,829 +2375,10022 @@ "node": ">=7.0.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/chance": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.11.tgz", + "integrity": "sha512-kqTg3WWywappJPqtgrdvbA380VoXO2eu9VCV895JgbyHsaErXdyHK9LOZ911OvAk6L0obK7kDk9CGs8+oBawVA==", "dev": true }, - "node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "engines": { - "node": ">= 14" + "node": ">=8" } }, - "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, "engines": { "node": ">=12" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, "engines": { - "node": ">=6" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "packages/quicktype-core": { - "version": "18.0.15", - "license": "Apache-2.0", + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "dependencies": { - "@glideapps/ts-necessities": "2.1.3", - "@types/urijs": "^1.19.25", - "browser-or-node": "^2.1.1", - "collection-utils": "^1.0.1", - "cross-fetch": "^4.0.0", - "is-url": "^1.2.4", - "js-base64": "^3.7.5", - "lodash": "^4.17.21", - "pako": "^1.0.6", - "pluralize": "^8.0.0", - "readable-stream": "4.5.2", - "unicode-properties": "^1.4.1", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^2.3.1" - }, - "devDependencies": { - "@types/browser-or-node": "^1.3.2", - "@types/js-base64": "^3.3.1", - "@types/node": "18.14.0", - "@types/pako": "^1.0.0", - "@types/pluralize": "0.0.30", - "@types/readable-stream": "4.0.10", - "@types/unicode-properties": "^1.3.0", - "@types/yaml": "^1.9.7", - "tslint": "^6.1.3", - "typescript": "4.9.5" + "color-name": "1.1.3" } }, - "packages/quicktype-core/node_modules/browser-or-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", - "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" + "node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, - "packages/quicktype-core/node_modules/js-base64": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz", - "integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==" + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "packages/quicktype-core/node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, "engines": { - "node": ">=4" + "node": ">=4.0.0" } }, - "packages/quicktype-graphql-input": { - "version": "18.0.15", - "license": "Apache-2.0", + "node_modules/command-line-usage": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", + "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", "dependencies": { - "collection-utils": "^1.0.1", - "graphql": "^0.11.7", - "quicktype-core": "file:../quicktype-core" + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^3.0.0", + "typical": "^7.1.1" }, - "devDependencies": { - "@types/graphql": "^0.11.7", - "@types/node": "18.14.0", - "tslint": "^6.1.3", - "typescript": "4.9.5" + "engines": { + "node": ">=12.20.0" } }, - "packages/quicktype-typescript-input": { - "version": "18.0.15", - "license": "Apache-2.0", + "node_modules/command-line-usage/node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/core-js-pure": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.36.1.tgz", + "integrity": "sha512-NXCvHvSVYSrewP0L5OhltzXeWFJLo2AL2TYnj6iLV3Bw8mM62wAQMNgUCRI6EBu6hVVpbCxmOPlxh1Ikw2PfUA==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "dev": true, "dependencies": { - "@mark.probst/typescript-json-schema": "0.55.0", - "quicktype-core": "file:../quicktype-core", - "typescript": "4.9.5" + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, - "devDependencies": { - "@types/node": "18.14.0", - "tslint": "^6.1.3" + "engines": { + "node": ">=14" } }, - "packages/quicktype-typescript-input/node_modules/@glideapps/ts-necessities": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.1.2.tgz", - "integrity": "sha512-tLjfhinr6doUBcWi7BWnkT2zT6G5UhiZftsiIH6xVvykeXE+FU7Wr0MyqwmqideWlDD5rG+VjVLptLviGo04CA==" + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, - "packages/quicktype-typescript-input/node_modules/isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "packages/quicktype-typescript-input/node_modules/node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "node_modules/create-eslint-index": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/create-eslint-index/-/create-eslint-index-1.0.0.tgz", + "integrity": "sha512-nXvJjnfDytOOaPOonX0h0a1ggMoqrhdekGeZkD6hkcWYvlCWhU719tKFVh8eU04CnMwu3uwe1JjwuUF2C3k2qg==", + "dev": true, "dependencies": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + "lodash.get": "^4.3.0" + }, + "engines": { + "node": ">=4.0.0" } }, - "packages/quicktype-typescript-input/node_modules/quicktype-core": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-20.0.0.tgz", - "integrity": "sha512-zuvQAk/i4STnhLC4t3nNWPr6u5ArHBW+TME3jA7YQQMp1UdDsFD+4lzqt49b73aYhhmrk9BlO/fX7PcRR5l6YQ==", + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "dependencies": { - "@glideapps/ts-necessities": "2.1.2", - "@types/urijs": "^1.19.8", - "browser-or-node": "^1.2.1", - "collection-utils": "^1.0.1", - "is-url": "^1.2.4", - "isomorphic-fetch": "^2.2.1", - "js-base64": "^2.4.3", - "lodash": "^4.17.21", - "pako": "^1.0.6", - "pluralize": "^7.0.0", - "readable-stream": "2.3.7", - "unicode-properties": "^1.4.1", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^1.5.0" + "node-fetch": "^2.6.12" } }, - "packages/quicktype-typescript-input/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "packages/quicktype-typescript-input/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } - } - }, - "dependencies": { - "@75lb/deep-merge": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.1.tgz", - "integrity": "sha512-xvgv6pkMGBA6GwdyJbNAnDmfAIR/DfWhrj9jgWh3TY7gRm3KO46x/GPjRg6wJ0nOepwqrNxFfojebh0Df4h4Tw==", + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dataloader": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", + "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-equal": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", + "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.1", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dset": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", + "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.717", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz", + "integrity": "sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/enhance-visitors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/enhance-visitors/-/enhance-visitors-1.0.0.tgz", + "integrity": "sha512-+29eJLiUixTEDRaZ35Vu8jP3gPLNcQQkQkOQjLp2X+6cZGGPDD/uasbFzvLsJKnGZnvmyZ0srxudwOtskHeIDA==", + "dev": true, + "dependencies": { + "lodash": "^4.13.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", + "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.5", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-ast-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-ast-utils/-/eslint-ast-utils-1.1.0.tgz", + "integrity": "sha512-otzzTim2/1+lVrlH19EfQQJEhVJSu0zOb9ygb3iapN6UlyaDtyRq4b5U1FuW0v1lRa9Fp/GJyHkSwm6NqABgCA==", + "dev": true, + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.zip": "^4.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz", + "integrity": "sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==", + "dev": true, + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-canonical": { + "version": "41.4.2", + "resolved": "https://registry.npmjs.org/eslint-config-canonical/-/eslint-config-canonical-41.4.2.tgz", + "integrity": "sha512-ayP7OPe7Mh0Vf1K8PXQshekyeM3dNcEVwoJAu5ozrZXftaY36NPaH57Oj1FcmMzr2gpc3WbjQ5frVqxnqjnKMg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/eslint-parser": "^7.22.15", + "@babel/eslint-plugin": "^7.22.10", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@graphql-eslint/eslint-plugin": "^3.20.1", + "@next/eslint-plugin-next": "^13.5.4", + "@rushstack/eslint-patch": "^1.5.1", + "@typescript-eslint/eslint-plugin": "^6.7.5", + "@typescript-eslint/parser": "^6.7.5", + "eslint-config-prettier": "^9.0.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-ava": "^14.0.0", + "eslint-plugin-canonical": "^4.14.0", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-fp": "^2.3.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jest": "^27.4.2", + "eslint-plugin-jsdoc": "^46.8.2", + "eslint-plugin-jsonc": "^2.10.0", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-lodash": "^7.4.0", + "eslint-plugin-mocha": "^10.2.0", + "eslint-plugin-modules-newline": "0.0.6", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-regexp": "^1.15.0", + "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-typescript-sort-keys": "^3.0.0", + "eslint-plugin-unicorn": "^48.0.1", + "eslint-plugin-vitest": "^0.3.2", + "eslint-plugin-yml": "^1.10.0", + "eslint-plugin-zod": "^1.4.0", + "prettier": "^3.0.3", + "ramda": "^0.29.1", + "yaml-eslint-parser": "^1.2.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "eslint": "^8.30.0" + } + }, + "node_modules/eslint-config-canonical/node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-canonical/node_modules/eslint-plugin-canonical": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-canonical/-/eslint-plugin-canonical-4.18.0.tgz", + "integrity": "sha512-0Egc0FKOnCRdu3bFEJhfHkdkusIgW0UxdemukkowZQnQsnf12FHSJ7K26b+tZ5pKB7cTyECSaqvEpoIJfplX4g==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^6.1.0", + "chance": "^1.1.11", + "debug": "^4.3.4", + "eslint-import-resolver-typescript": "^3.5.3", + "eslint-module-utils": "^2.7.4", + "is-get-set-prop": "^1.0.0", + "is-js-type": "^2.0.0", + "is-obj-prop": "^1.0.0", + "is-proto-prop": "^2.0.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "recast": "^0.23.2", + "roarr": "^7.14.2", + "ts-unused-exports": "^9.0.3", + "xregexp": "^5.1.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/eslint-config-canonical/node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-config-canonical/node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/eslint-config-canonical/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/eslint-config-prettier": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", + "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", + "dev": true, + "dependencies": { + "get-stdin": "^6.0.0" + }, + "bin": { + "eslint-config-prettier-check": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=3.14.1" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-ava": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-ava/-/eslint-plugin-ava-14.0.0.tgz", + "integrity": "sha512-XmKT6hppaipwwnLVwwvQliSU6AF1QMHiNoLD5JQfzhUhf0jY7CO0O624fQrE+Y/fTb9vbW8r77nKf7M/oHulxw==", + "dev": true, + "dependencies": { + "enhance-visitors": "^1.0.0", + "eslint-utils": "^3.0.0", + "espree": "^9.0.0", + "espurify": "^2.1.1", + "import-modules": "^2.1.0", + "micro-spelling-correcter": "^1.1.1", + "pkg-dir": "^5.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=14.17 <15 || >=16.4" + }, + "peerDependencies": { + "eslint": ">=8.26.0" + } + }, + "node_modules/eslint-plugin-ava/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-plugin-canonical": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-canonical/-/eslint-plugin-canonical-3.4.0.tgz", + "integrity": "sha512-akY2RpJD3VC2XXsU/02VsbzkHfybsZTsruOKPI7pJzQ+lZaS3UGM1H0vUKf0itXsbMHHJbIT78hUXU2d2HemZQ==", + "dev": true, + "dependencies": { + "is-get-set-prop": "^1.0.0", + "is-js-type": "^2.0.0", + "is-obj-prop": "^1.0.0", + "is-proto-prop": "^2.0.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "ts-unused-exports": "^9.0.3", + "xregexp": "^5.1.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/eslint-plugin-cypress": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz", + "integrity": "sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w==", + "dev": true, + "dependencies": { + "globals": "^13.20.0" + }, + "peerDependencies": { + "eslint": ">= 3.2.1" + } + }, + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "engines": { + "node": ">=6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@babel/plugin-syntax-flow": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.9", + "eslint": "^8.1.0" + } + }, + "node_modules/eslint-plugin-fp": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-fp/-/eslint-plugin-fp-2.3.0.tgz", + "integrity": "sha512-3n2oHibwoIxAht9/+ZaTldhI6brXORgl8oNXqZd+d9xuAQt2SBJ2/aml0oQRMWvXrgsz2WG6wfC++NjzSG3prA==", + "dev": true, + "dependencies": { + "create-eslint-index": "^1.0.0", + "eslint-ast-utils": "^1.0.0", + "lodash": "^4.13.1", + "req-all": "^0.1.0" + }, + "engines": { + "node": ">=4.0.0" + }, + "peerDependencies": { + "eslint": ">=3" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", + "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-json": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-3.1.0.tgz", + "integrity": "sha512-MrlG2ynFEHe7wDGwbUuFPsaT2b1uhuEFhJ+W1f1u+1C2EkXmTYJp4B1aAdQQ8M+CC3t//N/oRKiIVw14L2HR1g==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21", + "vscode-json-languageservice": "^4.1.6" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/eslint-plugin-jsonc": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.14.1.tgz", + "integrity": "sha512-Tei6G4N7pZulP5MHi0EIdtseiCqUPkDMd0O8Zrw4muMIlsjJ5/B9X+U3Pfo6B7l0mTL9LN9FwuWT70dRJ6z7tg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "eslint-compat-utils": "^0.5.0", + "espree": "^9.6.1", + "graphemer": "^1.4.0", + "jsonc-eslint-parser": "^2.0.4", + "natural-compare": "^1.4.0", + "synckit": "^0.6.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/eslint-plugin-lodash": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-lodash/-/eslint-plugin-lodash-7.4.0.tgz", + "integrity": "sha512-Tl83UwVXqe1OVeBRKUeWcfg6/pCW1GTRObbdnbEJgYwjxp5Q92MEWQaH9+dmzbRt6kvYU1Mp893E79nJiCSM8A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": ">=2" + } + }, + "node_modules/eslint-plugin-mocha": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.1.tgz", + "integrity": "sha512-G85ALUgKaLzuEuHhoW3HVRgPTmia6njQC3qCG6CEvA8/Ja9PDZnRZOuzekMki+HaViEQXINuYsmhp5WR5/4MfA==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "globals": "^13.24.0", + "rambda": "^7.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-modules-newline": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-modules-newline/-/eslint-plugin-modules-newline-0.0.6.tgz", + "integrity": "sha512-69NpBr68U6pmXL+y+KHl/64PwRarceC3/sCNUVxRbe0gPI32SIw8AtdpkqNiJYCa2yMd4lRrkrnU09Yio7KVzA==", + "dev": true, + "dependencies": { + "requireindex": "~1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "node_modules/eslint-plugin-node/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-plugin-node/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-node/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-regexp": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-1.15.0.tgz", + "integrity": "sha512-YEtQPfdudafU7RBIFci81R/Q1yErm0mVh3BkGnXD2Dk8DLwTFdc2ITYH1wCnHKim2gnHfPFgrkh+b2ozyyU7ag==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "comment-parser": "^1.1.2", + "grapheme-splitter": "^1.0.4", + "jsdoctypeparser": "^9.0.0", + "refa": "^0.11.0", + "regexp-ast-analysis": "^0.6.0", + "scslre": "^0.2.0" + }, + "engines": { + "node": "^12 || >=14" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-plugin-typescript-sort-keys": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-typescript-sort-keys/-/eslint-plugin-typescript-sort-keys-3.2.0.tgz", + "integrity": "sha512-GutszvriaVtwmn7pQjuj9/9o0iXhD7XZs0/424+zsozdRr/fdg5e8206t478Vnqnqi1GjuxcAolj1kf74KnhPA==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "^5.0.0", + "json-schema": "^0.4.0", + "natural-compare-lite": "^1.4.0" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6 || ^7", + "eslint": "^7 || ^8", + "typescript": "^3 || ^4 || ^5" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "48.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-48.0.1.tgz", + "integrity": "sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "@eslint-community/eslint-utils": "^4.4.0", + "ci-info": "^3.8.0", + "clean-regexp": "^1.0.0", + "esquery": "^1.5.0", + "indent-string": "^4.0.0", + "is-builtin-module": "^3.2.1", + "jsesc": "^3.0.2", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "read-pkg-up": "^7.0.1", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.10.0", + "semver": "^7.5.4", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=8.44.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-vitest": { + "version": "0.3.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.3.26.tgz", + "integrity": "sha512-oxe5JSPgRjco8caVLTh7Ti8PxpwJdhSV0hTQAmkFcNcmy/9DnqLB/oNVRA11RmVRP//2+jIIT6JuBEcpW3obYg==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^7.1.1" + }, + "engines": { + "node": "^18.0.0 || >= 20.0.0" + }, + "peerDependencies": { + "eslint": ">=8.0.0", + "vitest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/scope-manager": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.4.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-plugin-yml": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-1.13.2.tgz", + "integrity": "sha512-1i71VhmsG5UxE41rIJmJjhlTTxYy7upAY5Hqj8AdBc7rfJzRIZr3a2spuOS8+N7ZDCWsHAWY3J6lzQNQHDv6Uw==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-compat-utils": "^0.5.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^1.2.1" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-zod": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-zod/-/eslint-plugin-zod-1.4.0.tgz", + "integrity": "sha512-i9WzQGw2X5fQcuQh33mA8DQjZJM/yuyZvs1Fc5EyTidX7Ed/g832+1FEQ4u5gtXy+jZ+DVsB5+oMHj4tIOfeZg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=8.1.0" + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "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/espurify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/espurify/-/espurify-2.1.1.tgz", + "integrity": "sha512-zttWvnkhcDyGOhSH4vO2qCBILpdCMv/MX8lp4cqgRkQoDRGK2oZxi2GfWhlP2dIXmk7BaKeOTuzbHhyC68o8XQ==", + "dev": true + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/exec-sh": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz", + "integrity": "sha512-aLt95pexaugVtQerpmE51+4QfWrNc304uez7jvj6fWnN8GeEHpttB8F36n8N7uVhUMbH/1enbxQ9HImZ4w/9qg==", + "dev": true, + "dependencies": { + "merge": "^1.1.3" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/extract-files": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz", + "integrity": "sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==", + "dev": true, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "funding": { + "url": "https://github.com/sponsors/jaydenseric" + } + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-printf": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", + "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", + "dev": true, + "dependencies": { + "boolean": "^3.1.4" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dev": true, + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fast-url-parser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-set-props": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-set-props/-/get-set-props-0.1.0.tgz", + "integrity": "sha512-7oKuKzAGKj0ag+eWZwcGw2fjiZ78tXnXQoBgY0aU7ZOxTu4bB7hSuQSDgtKy978EDH062P5FmD2EWiDpQS9K9Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphql": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.11.7.tgz", + "integrity": "sha512-x7uDjyz8Jx+QPbpCFCMQ8lltnQa4p4vSYHx6ADe8rVYRTdsyhCJbvSty5DAsLVmU6cGakl+r8HQYolKHxk/tiw==", + "dependencies": { + "iterall": "1.1.3" + } + }, + "node_modules/graphql-config": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-4.5.0.tgz", + "integrity": "sha512-x6D0/cftpLUJ0Ch1e5sj1TZn6Wcxx4oMfmhaG9shM0DKajA9iR+j1z86GSTQ19fShbGvrSSvbIQsHku6aQ6BBw==", + "dev": true, + "dependencies": { + "@graphql-tools/graphql-file-loader": "^7.3.7", + "@graphql-tools/json-file-loader": "^7.3.7", + "@graphql-tools/load": "^7.5.5", + "@graphql-tools/merge": "^8.2.6", + "@graphql-tools/url-loader": "^7.9.7", + "@graphql-tools/utils": "^9.0.0", + "cosmiconfig": "8.0.0", + "jiti": "1.17.1", + "minimatch": "4.2.3", + "string-env-interpolation": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "cosmiconfig-toml-loader": "^1.0.0", + "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "cosmiconfig-toml-loader": { + "optional": true + } + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/graphql-file-loader": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.5.17.tgz", + "integrity": "sha512-hVwwxPf41zOYgm4gdaZILCYnKB9Zap7Ys9OhY1hbwuAuC4MMNY9GpUjoTU3CQc3zUiPoYStyRtUGkHSJZ3HxBw==", + "dev": true, + "dependencies": { + "@graphql-tools/import": "6.7.18", + "@graphql-tools/utils": "^9.2.1", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/graphql-file-loader/node_modules/@graphql-tools/import": { + "version": "6.7.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-6.7.18.tgz", + "integrity": "sha512-XQDdyZTp+FYmT7as3xRWH/x8dx0QZA2WZqfMF5EWb36a0PiH7WwlRQYIdyYXj8YCLpiWkeBXgBRHmMnwEYR8iQ==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "resolve-from": "5.0.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/json-file-loader": { + "version": "7.4.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-7.4.18.tgz", + "integrity": "sha512-AJ1b6Y1wiVgkwsxT5dELXhIVUPs/u3VZ8/0/oOtpcoyO/vAeM5rOvvWegzicOOnQw8G45fgBRMkkRfeuwVt6+w==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/load": { + "version": "7.8.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-7.8.14.tgz", + "integrity": "sha512-ASQvP+snHMYm+FhIaLxxFgVdRaM0vrN9wW2BKInQpktwWTXVyk+yP5nQUCEGmn0RTdlPKrffBaigxepkEAJPrg==", + "dev": true, + "dependencies": { + "@graphql-tools/schema": "^9.0.18", + "@graphql-tools/utils": "^9.2.1", + "p-limit": "3.1.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/load/node_modules/@graphql-tools/schema": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", + "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "dev": true, + "dependencies": { + "@graphql-tools/merge": "^8.4.1", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader": { + "version": "7.17.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-7.17.18.tgz", + "integrity": "sha512-ear0CiyTj04jCVAxi7TvgbnGDIN2HgqzXzwsfcqiVg9cvjT40NcMlZ2P1lZDgqMkZ9oyLTV8Bw6j+SyG6A+xPw==", + "dev": true, + "dependencies": { + "@ardatan/sync-fetch": "^0.0.1", + "@graphql-tools/delegate": "^9.0.31", + "@graphql-tools/executor-graphql-ws": "^0.0.14", + "@graphql-tools/executor-http": "^0.1.7", + "@graphql-tools/executor-legacy-ws": "^0.0.11", + "@graphql-tools/utils": "^9.2.1", + "@graphql-tools/wrap": "^9.4.2", + "@types/ws": "^8.0.0", + "@whatwg-node/fetch": "^0.8.0", + "isomorphic-ws": "^5.0.0", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.11", + "ws": "^8.12.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/delegate": { + "version": "9.0.35", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-9.0.35.tgz", + "integrity": "sha512-jwPu8NJbzRRMqi4Vp/5QX1vIUeUPpWmlQpOkXQD2r1X45YsVceyUUBnktCrlJlDB4jPRVy7JQGwmYo3KFiOBMA==", + "dev": true, + "dependencies": { + "@graphql-tools/batch-execute": "^8.5.22", + "@graphql-tools/executor": "^0.0.20", + "@graphql-tools/schema": "^9.0.19", + "@graphql-tools/utils": "^9.2.1", + "dataloader": "^2.2.2", + "tslib": "^2.5.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/delegate/node_modules/@graphql-tools/batch-execute": { + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.5.22.tgz", + "integrity": "sha512-hcV1JaY6NJQFQEwCKrYhpfLK8frSXDbtNMoTur98u10Cmecy1zrqNKSqhEyGetpgHxaJRqszGzKeI3RuroDN6A==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "dataloader": "^2.2.2", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/delegate/node_modules/@graphql-tools/executor": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-0.0.20.tgz", + "integrity": "sha512-GdvNc4vszmfeGvUqlcaH1FjBoguvMYzxAfT6tDd4/LgwymepHhinqLNA5otqwVLW+JETcDaK7xGENzFomuE6TA==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "@graphql-typed-document-node/core": "3.2.0", + "@repeaterjs/repeater": "^3.0.4", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/delegate/node_modules/@graphql-tools/schema": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", + "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "dev": true, + "dependencies": { + "@graphql-tools/merge": "^8.4.1", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/executor-graphql-ws": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-0.0.14.tgz", + "integrity": "sha512-P2nlkAsPZKLIXImFhj0YTtny5NQVGSsKnhi7PzXiaHSXc6KkzqbWZHKvikD4PObanqg+7IO58rKFpGXP7eeO+w==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "@repeaterjs/repeater": "3.0.4", + "@types/ws": "^8.0.0", + "graphql-ws": "5.12.1", + "isomorphic-ws": "5.0.0", + "tslib": "^2.4.0", + "ws": "8.13.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/executor-http": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-0.1.10.tgz", + "integrity": "sha512-hnAfbKv0/lb9s31LhWzawQ5hghBfHS+gYWtqxME6Rl0Aufq9GltiiLBcl7OVVOnkLF0KhwgbYP1mB5VKmgTGpg==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "@repeaterjs/repeater": "^3.0.4", + "@whatwg-node/fetch": "^0.8.1", + "dset": "^3.1.2", + "extract-files": "^11.0.0", + "meros": "^1.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/executor-legacy-ws": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-0.0.11.tgz", + "integrity": "sha512-4ai+NnxlNfvIQ4c70hWFvOZlSUN8lt7yc+ZsrwtNFbFPH/EroIzFMapAxM9zwyv9bH38AdO3TQxZ5zNxgBdvUw==", + "dev": true, + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "@types/ws": "^8.0.0", + "isomorphic-ws": "5.0.0", + "tslib": "^2.4.0", + "ws": "8.13.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/wrap": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-9.4.2.tgz", + "integrity": "sha512-DFcd9r51lmcEKn0JW43CWkkI2D6T9XI1juW/Yo86i04v43O9w2/k4/nx2XTJv4Yv+iXwUw7Ok81PGltwGJSDSA==", + "dev": true, + "dependencies": { + "@graphql-tools/delegate": "^9.0.31", + "@graphql-tools/schema": "^9.0.18", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/wrap/node_modules/@graphql-tools/schema": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", + "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "dev": true, + "dependencies": { + "@graphql-tools/merge": "^8.4.1", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "dev": true, + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/minimatch": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.3.tgz", + "integrity": "sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/graphql-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/graphql-config/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/graphql-config/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/graphql-depth-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/graphql-depth-limit/-/graphql-depth-limit-1.1.0.tgz", + "integrity": "sha512-+3B2BaG8qQ8E18kzk9yiSdAa75i/hnnOwgSeAxVJctGQPvmeiLtqKOYF6HETCyRjiF7Xfsyal0HbLlxCQkgkrw==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "graphql": "*" + } + }, + "node_modules/graphql-ws": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.12.1.tgz", + "integrity": "sha512-umt4f5NnMK46ChM2coO36PTFhHouBrK9stWWBczERguwYrGnPNxJ9dimU6IyOBfOkC6Izhkg4H8+F51W/8CYDg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": ">=0.11 <=16" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-modules": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-modules/-/import-modules-2.1.0.tgz", + "integrity": "sha512-8HEWcnkbGpovH9yInoisxaSoIg9Brbul+Ju3Kqe2UsYDUBJD/iQjSgEj0zPcTDPKfPp2fs5xlv1i+JSye/m1/A==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-builtin-module/node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-get-set-prop": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-get-set-prop/-/is-get-set-prop-1.0.0.tgz", + "integrity": "sha512-DvAYZ1ZgGUz4lzxKMPYlt08qAUqyG9ckSg2pIjfvcQ7+pkVNUHk8yVLXOnCLe5WKXhLop8oorWFBJHpwWQpszQ==", + "dev": true, + "dependencies": { + "get-set-props": "^0.1.0", + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-js-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-js-type/-/is-js-type-2.0.0.tgz", + "integrity": "sha512-Aj13l47+uyTjlQNHtXBV8Cji3jb037vxwMWCgopRR8h6xocgBGW3qG8qGlIOEmbXQtkKShKuBM9e8AA1OeQ+xw==", + "dev": true, + "dependencies": { + "js-types": "^1.0.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj-prop": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-obj-prop/-/is-obj-prop-1.0.0.tgz", + "integrity": "sha512-5Idb61slRlJlsAzi0Wsfwbp+zZY+9LXKUAZpvT/1ySw+NxKLRWfa0Bzj+wXI3fX5O9hiddm5c3DAaRSNP/yl2w==", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0", + "obj-props": "^1.0.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-proto-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-2.0.0.tgz", + "integrity": "sha512-jl3NbQ/fGLv5Jhan4uX+Ge9ohnemqyblWVVCpAvtTQzNFvV2xhJq+esnkIbYQ9F1nITXoLfDDQLp7LBw/zzncg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0", + "proto-props": "^2.0.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "dev": true, + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/iterall": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz", + "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==" + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jiti": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.17.1.tgz", + "integrity": "sha512-NZIITw8uZQFuzQimqjUxIrIcEdxYDFIe/0xYfIlVXTkiBjjyBEvgasj5bb0/cHtPRD/NziPbT312sFrkI5ALpw==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-base64": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", + "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-types": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/js-types/-/js-types-1.0.0.tgz", + "integrity": "sha512-bfwqBW9cC/Lp7xcRpug7YrXm0IVw+T9e3g4mCYnv0Pjr3zIzU9PCQElYU9oSGAWzXlbdl9X5SAMPejO9sxkeUw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoctypeparser": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz", + "integrity": "sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==", + "dev": true, + "bin": { + "jsdoctypeparser": "bin/jsdoctypeparser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-eslint-parser": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz", + "integrity": "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==", + "dev": true, + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.assignwith": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", + "integrity": "sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "node_modules/lodash.lowercase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.lowercase/-/lodash.lowercase-4.3.0.tgz", + "integrity": "sha512-UcvP1IZYyDKyEL64mmrwoA1AbFu5ahojhTtkOUr1K9dbuxzS9ev8i4TxMMGCqRC9TE8uDaSoufNAXxRPNTseVA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", + "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==" + }, + "node_modules/merge": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/meros": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.0.tgz", + "integrity": "sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==", + "dev": true, + "engines": { + "node": ">=13" + }, + "peerDependencies": { + "@types/node": ">=13" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/micro-spelling-correcter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/micro-spelling-correcter/-/micro-spelling-correcter-1.1.1.tgz", + "integrity": "sha512-lkJ3Rj/mtjlRcHk6YyCbvZhyWTOzdBvTHsxMmZSk5jxN1YyVSQ+JETAom55mdzfcyDrY/49Z7UCW760BK30crg==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/obj-props": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/obj-props/-/obj-props-1.4.0.tgz", + "integrity": "sha512-p7p/7ltzPDiBs6DqxOrIbtRdwxxVRBj5ROukeNb9RgA+fawhrz5n2hpNz8DDmYR//tviJSj7nUnlppGmONkjiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-equal": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", + "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "engines": { + "node": ">=4" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-timeout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/promise-timeout/-/promise-timeout-1.3.0.tgz", + "integrity": "sha512-5yANTE0tmi5++POym6OgtFmwfDvOXABD9oj/jLQr5GPEyuNEb7jH4wbbANJceJid49jwhi1RddxnhnEAb/doqg==", + "dev": true + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proto-props": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proto-props/-/proto-props-2.0.0.tgz", + "integrity": "sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", + "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", + "dev": true, + "dependencies": { + "tslib": "^2.6.1" + } + }, + "node_modules/pvtsutils/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quicktype-core": { + "resolved": "packages/quicktype-core", + "link": true + }, + "node_modules/quicktype-graphql-input": { + "resolved": "packages/quicktype-graphql-input", + "link": true + }, + "node_modules/quicktype-typescript-input": { + "resolved": "packages/quicktype-typescript-input", + "link": true + }, + "node_modules/rambda": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", + "integrity": "sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==", + "dev": true + }, + "node_modules/ramda": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", + "integrity": "sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/recast": { + "version": "0.23.6", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.6.tgz", + "integrity": "sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/refa": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.11.0.tgz", + "integrity": "sha512-486O8/pQXwj9jV0mVvUnTsxq0uknpBnNJ0eCUhkZqJRQ8KutrT1PhzmumdCeM1hSBF2eMlFPmwECRER4IbKXlQ==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.0" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/regexp-ast-analysis": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.6.0.tgz", + "integrity": "sha512-OLxjyjPkVH+rQlBLb1I/P/VTmamSjGkvN5PTV5BXP432k3uVz727J7H29GA5IFiY0m7e1xBN7049Wn59FY3DEQ==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.0", + "refa": "^0.11.0" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regjsparser": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz", + "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true + }, + "node_modules/req-all": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/req-all/-/req-all-0.1.0.tgz", + "integrity": "sha512-ZdvPr8uXy9ujX3KujwE2P1HWkMYgogIhqeAeyb47MqWjSfyxERSm0TNbN/IapCCmWDufXab04AYrRgObaJCJ6Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireindex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", + "integrity": "sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/roarr": { + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-7.21.1.tgz", + "integrity": "sha512-3niqt5bXFY1InKU8HKWqqYTYjtrBaxBMnXELXCXUYgtNYGUtZM5rB46HIC430AyacL95iEniGf7RgqsesykLmQ==", + "dev": true, + "dependencies": { + "fast-printf": "^1.6.9", + "safe-stable-stringify": "^2.4.3", + "semver-compare": "^1.0.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/scslre": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.2.0.tgz", + "integrity": "sha512-4hc49fUMmX3jM0XdFUAPBrs1xwEcdHa0KyjEsjFs+Zfc66mpFpq5YmRgDtl+Ffo6AtJIilfei+yKw8fUn3N88w==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.0", + "refa": "^0.11.0", + "regexp-ast-analysis": "^0.6.0" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" + }, + "node_modules/stream-json": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.8.0.tgz", + "integrity": "sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/stream-read-all": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz", + "integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==", + "engines": { + "node": ">=10" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-env-interpolation": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz", + "integrity": "sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==", + "dev": true + }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "dev": true + }, + "node_modules/string-to-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-3.0.1.tgz", + "integrity": "sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg==", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, + "node_modules/string-to-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.6.2.tgz", + "integrity": "sha512-Vhf+bUa//YSTYKseDiiEuQmhGCoIF3CVBhunm3r/DQnYiGT4JssmnKQc44BIyOZRK2pKjXXAgbhfmbeoC9CJpA==", + "dev": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/synckit/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/table-layout": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz", + "integrity": "sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==", + "dependencies": { + "@75lb/deep-merge": "^1.1.1", + "array-back": "^6.2.2", + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.0", + "stream-read-all": "^3.0.1", + "typical": "^7.1.1", + "wordwrapjs": "^5.1.0" + }, + "bin": { + "table-layout": "bin/cli.js" + }, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tiny-inflate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.2.tgz", + "integrity": "sha1-k9nez/yIBb1X6uQxDwt0Xptvs6c=" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-unused-exports": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.5.tgz", + "integrity": "sha512-1XAXaH2i4Al/aZO06pWDn9MUgTN0KQi+fvWudiWfHUTHAav45gzrx7Xq6JAsu6+LoMlVoyGvNvZSPW3KTjDncA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "tsconfig-paths": "^3.9.0" + }, + "bin": { + "ts-unused-exports": "bin/ts-unused-exports" + }, + "funding": { + "url": "https://github.com/pzavolinsky/ts-unused-exports?sponsor=1" + }, + "peerDependencies": { + "typescript": ">=3.8.3" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": false + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-properties/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" + }, + "node_modules/unicode-properties/node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unixify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", + "integrity": "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==", + "dev": true, + "dependencies": { + "normalize-path": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" + }, + "node_modules/urlpattern-polyfill": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz", + "integrity": "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/value-or-promise": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", + "integrity": "sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/vscode-json-languageservice": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", + "integrity": "sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-languageserver-textdocument": "^1.0.3", + "vscode-languageserver-types": "^3.16.0", + "vscode-nls": "^5.0.0", + "vscode-uri": "^3.0.3" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "dev": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true + }, + "node_modules/vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "dev": true + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true + }, + "node_modules/watch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", + "integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=", + "dev": true, + "dependencies": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webcrypto-core": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", + "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + } + }, + "node_modules/webcrypto-core/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "node_modules/wordwrapjs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", + "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xregexp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.1.tgz", + "integrity": "sha512-fKXeVorD+CzWvFs7VBuKTYIW63YD1e1osxwQ8caZ6o1jg6pDAbABDG54LCIq0j5cy7PjRvGIq6sef9DYPXpncg==", + "dev": true, + "dependencies": { + "@babel/runtime-corejs3": "^7.16.5" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-eslint-parser": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.2.2.tgz", + "integrity": "sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/quicktype-core": { + "version": "18.0.15", + "license": "Apache-2.0", + "dependencies": { + "@glideapps/ts-necessities": "2.1.3", + "@types/urijs": "^1.19.25", + "browser-or-node": "^2.1.1", + "collection-utils": "^1.0.1", + "cross-fetch": "^4.0.0", + "is-url": "^1.2.4", + "js-base64": "^3.7.5", + "lodash": "^4.17.21", + "pako": "^1.0.6", + "pluralize": "^8.0.0", + "readable-stream": "4.5.2", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^2.3.1" + }, + "devDependencies": { + "@types/browser-or-node": "^1.3.2", + "@types/js-base64": "^3.3.1", + "@types/node": "18.14.0", + "@types/pako": "^1.0.0", + "@types/pluralize": "0.0.30", + "@types/readable-stream": "4.0.10", + "@types/unicode-properties": "^1.3.0", + "@types/yaml": "^1.9.7", + "tslint": "^6.1.3", + "typescript": "4.9.5" + } + }, + "packages/quicktype-core/node_modules/browser-or-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", + "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" + }, + "packages/quicktype-core/node_modules/js-base64": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz", + "integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==" + }, + "packages/quicktype-core/node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "engines": { + "node": ">=4" + } + }, + "packages/quicktype-graphql-input": { + "version": "18.0.15", + "license": "Apache-2.0", + "dependencies": { + "collection-utils": "^1.0.1", + "graphql": "^0.11.7", + "quicktype-core": "file:../quicktype-core" + }, + "devDependencies": { + "@types/graphql": "^0.11.7", + "@types/node": "18.14.0", + "tslint": "^6.1.3", + "typescript": "4.9.5" + } + }, + "packages/quicktype-typescript-input": { + "version": "18.0.15", + "license": "Apache-2.0", + "dependencies": { + "@mark.probst/typescript-json-schema": "0.55.0", + "quicktype-core": "file:../quicktype-core", + "typescript": "4.9.5" + }, + "devDependencies": { + "@types/node": "18.14.0", + "tslint": "^6.1.3" + } + }, + "packages/quicktype-typescript-input/node_modules/@glideapps/ts-necessities": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.1.2.tgz", + "integrity": "sha512-tLjfhinr6doUBcWi7BWnkT2zT6G5UhiZftsiIH6xVvykeXE+FU7Wr0MyqwmqideWlDD5rG+VjVLptLviGo04CA==" + }, + "packages/quicktype-typescript-input/node_modules/isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", + "dependencies": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "packages/quicktype-typescript-input/node_modules/node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dependencies": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "packages/quicktype-typescript-input/node_modules/quicktype-core": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-20.0.0.tgz", + "integrity": "sha512-zuvQAk/i4STnhLC4t3nNWPr6u5ArHBW+TME3jA7YQQMp1UdDsFD+4lzqt49b73aYhhmrk9BlO/fX7PcRR5l6YQ==", + "dependencies": { + "@glideapps/ts-necessities": "2.1.2", + "@types/urijs": "^1.19.8", + "browser-or-node": "^1.2.1", + "collection-utils": "^1.0.1", + "is-url": "^1.2.4", + "isomorphic-fetch": "^2.2.1", + "js-base64": "^2.4.3", + "lodash": "^4.17.21", + "pako": "^1.0.6", + "pluralize": "^7.0.0", + "readable-stream": "2.3.7", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^1.5.0" + } + }, + "packages/quicktype-typescript-input/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "packages/quicktype-typescript-input/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "@75lb/deep-merge": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.1.tgz", + "integrity": "sha512-xvgv6pkMGBA6GwdyJbNAnDmfAIR/DfWhrj9jgWh3TY7gRm3KO46x/GPjRg6wJ0nOepwqrNxFfojebh0Df4h4Tw==", + "requires": { + "lodash.assignwith": "^4.2.0", + "typical": "^7.1.1" + }, + "dependencies": { + "typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==" + } + } + }, + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@ardatan/sync-fetch": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@ardatan/sync-fetch/-/sync-fetch-0.0.1.tgz", + "integrity": "sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA==", + "dev": true, + "requires": { + "node-fetch": "^2.6.1" + } + }, + "@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "requires": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + } + }, + "@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "dev": true + }, + "@babel/core": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", + "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/eslint-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.1.tgz", + "integrity": "sha512-d5guuzMlPeDfZIbpQ8+g1NaCNuAGBBGNECh0HVqz1sjOeVLh2CEaifuOysCH18URW6R7pqXINvf5PaR/dC6jLQ==", + "dev": true, + "requires": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/eslint-plugin": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.23.5.tgz", + "integrity": "sha512-03+E/58Hoo/ui69gR+beFdGpplpoVK0BSIdke2iw4/Bz7eGN0ssRenNlnU4nmbkowNQOPCStKSwFr8H6DiY49g==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0" + } + }, + "@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dev": true, + "requires": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "requires": { + "@babel/types": "^7.24.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "dev": true, + "requires": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + } + }, + "@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "dev": true + }, + "@babel/plugin-syntax-flow": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", + "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + } + }, + "@babel/runtime": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", + "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/runtime-corejs3": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.1.tgz", + "integrity": "sha512-T9ko/35G+Bkl+win48GduaPlhSlOjjE5s1TeiEcD+QpxlLQnoEfb/nO/T+TQqkm+ipFwORn+rB8w14iJ/uD0bg==", + "dev": true, + "requires": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + } + }, + "@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, + "requires": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + } + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true + }, + "@glideapps/ts-necessities": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.1.3.tgz", + "integrity": "sha512-q9U8v/n9qbkd2zDYjuX3qtlbl+OIyI9zF+zQhZjfYOE9VMDH7tfcUSJ9p0lXoY3lxmGFne09yi4iiNeQUwV7AA==" + }, + "@graphql-eslint/eslint-plugin": { + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@graphql-eslint/eslint-plugin/-/eslint-plugin-3.20.1.tgz", + "integrity": "sha512-RbwVlz1gcYG62sECR1u0XqMh8w5e5XMCCZoMvPQ3nJzEBCTfXLGX727GBoRmSvY1x4gJmqNZ1lsOX7lZY14RIw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@graphql-tools/code-file-loader": "^7.3.6", + "@graphql-tools/graphql-tag-pluck": "^7.3.6", + "@graphql-tools/utils": "^9.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "fast-glob": "^3.2.12", + "graphql-config": "^4.4.0", + "graphql-depth-limit": "^1.1.0", + "lodash.lowercase": "^4.3.0", + "tslib": "^2.4.1" + }, + "dependencies": { + "@graphql-tools/code-file-loader": { + "version": "7.3.23", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-7.3.23.tgz", + "integrity": "sha512-8Wt1rTtyTEs0p47uzsPJ1vAtfAx0jmxPifiNdmo9EOCuUPyQGEbMaik/YkqZ7QUFIEYEQu+Vgfo8tElwOPtx5Q==", + "dev": true, + "requires": { + "@graphql-tools/graphql-tag-pluck": "7.5.2", + "@graphql-tools/utils": "^9.2.1", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + } + }, + "@graphql-tools/graphql-tag-pluck": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-7.5.2.tgz", + "integrity": "sha512-RW+H8FqOOLQw0BPXaahYepVSRjuOHw+7IL8Opaa5G5uYGOBxoXR7DceyQ7BcpMgktAOOmpDNQ2WtcboChOJSRA==", + "dev": true, + "requires": { + "@babel/parser": "^7.16.8", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + } + }, + "@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "dev": true, + "requires": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "dev": true, + "requires": {} + }, + "@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@mark.probst/typescript-json-schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@mark.probst/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", + "integrity": "sha512-jI48mSnRgFQxXiE/UTUCVCpX8lK3wCFKLF1Ss2aEreboKNuLQGt3e0/YFqWVHe/WENxOaqiJvwOz+L/SrN2+qQ==", + "requires": { + "@types/json-schema": "^7.0.9", + "@types/node": "^16.9.2", + "glob": "^7.1.7", + "path-equal": "^1.1.2", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "yargs": "^17.1.1" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==" + }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" + } + } + }, + "@next/eslint-plugin-next": { + "version": "13.5.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.6.tgz", + "integrity": "sha512-ng7pU/DDsxPgT6ZPvuprxrkeew3XaRf4LAT4FabaEO/hAbvVx4P7wqnqdbTdDn1kgTvsI4tpIgT4Awn/m0bGbg==", + "dev": true, + "requires": { + "glob": "7.1.7" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "requires": { + "eslint-scope": "5.1.1" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@peculiar/asn1-schema": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", + "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "dev": true, + "requires": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "requires": { + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@peculiar/webcrypto": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", + "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.7.8" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true + }, + "@repeaterjs/repeater": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz", + "integrity": "sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==", + "dev": true + }, + "@rushstack/eslint-patch": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz", + "integrity": "sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==", + "dev": true + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + }, + "@tsconfig/node18": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-1.0.1.tgz", + "integrity": "sha512-sNFeK6X2ATlhlvzyH4kKYQlfHXE2f2/wxtB9ClvYXevWpmwkUT7VaSrjIN9E76Qebz8qP5JOJJ9jD3QoD/Z9TA==", + "dev": true + }, + "@types/browser-or-node": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/browser-or-node/-/browser-or-node-1.3.2.tgz", + "integrity": "sha512-CkvJrvVMI4ZHbiL+Df22Owzq1IYnHnoSrM8s6Dmy4MRdqvdFi9bHsIvyFrSGJPOxvFI9Y3MqY2gFCqIafJBcfw==", + "dev": true + }, + "@types/command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==", + "dev": true + }, + "@types/command-line-usage": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", + "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==", + "dev": true + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/graphql": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.11.8.tgz", + "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", + "dev": true + }, + "@types/js-base64": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/js-base64/-/js-base64-3.3.1.tgz", + "integrity": "sha512-Zw33oQNAvDdAN9b0IE5stH0y2MylYvtU7VVTKEJPxhyM2q57CVaNJhtJW258ah24NRtaiA23tptUmVn3dmTKpw==", + "dev": true, + "requires": { + "js-base64": "*" + } + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.197", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", + "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", + "dev": true + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "@types/node": { + "version": "18.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", + "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==" + }, + "@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "@types/pako": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.0.tgz", + "integrity": "sha1-6q6DZNG391LiY7w/1o3+yY5hNsU=", + "dev": true + }, + "@types/pluralize": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.30.tgz", + "integrity": "sha512-kVww6xZrW/db5BR9OqiT71J9huRdQ+z/r+LbDuT7/EK50mCmj5FoaIARnVv0rvjUS/YpDox0cDU9lpQT011VBA==", + "dev": true + }, + "@types/readable-stream": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", + "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", + "dev": true, + "requires": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "@types/shelljs": { + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.12.tgz", + "integrity": "sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==", + "dev": true, + "requires": { + "@types/glob": "~7.2.0", + "@types/node": "*" + } + }, + "@types/stream-chain": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stream-chain/-/stream-chain-2.0.1.tgz", + "integrity": "sha512-D+Id9XpcBpampptkegH7WMsEk6fUdf9LlCIX7UhLydILsqDin4L0QT7ryJR0oycwC7OqohIzdfcMHVZ34ezNGg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/stream-json": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@types/stream-json/-/stream-json-1.7.3.tgz", + "integrity": "sha512-Jqsyq5VPOTWorvEmzWhEWH5tJnHA+bB8vt/Zzb11vSDj8esfSHDMj2rbVjP0mfJQzl3YBJSXBBq08iiyaBK3KA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/stream-chain": "*" + } + }, + "@types/unicode-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/unicode-properties/-/unicode-properties-1.3.0.tgz", + "integrity": "sha512-kDVlxpdkCfgvzfXcglkr7j4OSMjCEEo/Jloj4tFuldYZpQ9Uypy7FGXPhNstoj4eGvhddwuu5n0EfI+XdWVoVA==", + "dev": true + }, + "@types/urijs": { + "version": "1.19.25", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", + "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==" + }, + "@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/yaml": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", + "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==", + "dev": true, + "requires": { + "yaml": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", + "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.62.0" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + } + }, + "@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "@whatwg-node/events": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.0.3.tgz", + "integrity": "sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA==", + "dev": true + }, + "@whatwg-node/fetch": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", + "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", + "dev": true, + "requires": { + "@peculiar/webcrypto": "^1.4.0", + "@whatwg-node/node-fetch": "^0.3.6", + "busboy": "^1.6.0", + "urlpattern-polyfill": "^8.0.0", + "web-streams-polyfill": "^3.2.1" + } + }, + "@whatwg-node/node-fetch": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.3.6.tgz", + "integrity": "sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA==", + "dev": true, + "requires": { + "@whatwg-node/events": "^0.0.3", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "fast-url-parser": "^1.1.3", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "requires": { + "dequal": "^2.0.3" + } + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + }, + "array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + } + }, + "array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dev": true, + "requires": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "requires": { + "possible-typed-array-names": "^1.0.0" + } + }, + "axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "dev": true + }, + "axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, + "requires": { + "dequal": "^2.0.3" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-or-node": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", + "integrity": "sha512-sVIA0cysIED0nbmNOm7sZzKfgN1rpFmrqvLZaFWspaBAftfQcezlC81G6j6U2RJf4Lh66zFxrCeOsvkUXIcPWg==" + }, + "browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "requires": { + "chalk": "^4.1.2" + } + }, + "chance": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.11.tgz", + "integrity": "sha512-kqTg3WWywappJPqtgrdvbA380VoXO2eu9VCV895JgbyHsaErXdyHK9LOZ911OvAk6L0obK7kDk9CGs8+oBawVA==", + "dev": true + }, + "ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true + }, + "clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + }, + "dependencies": { + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + } + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", + "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", + "requires": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^3.0.0", + "typical": "^7.1.1" + }, + "dependencies": { + "array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==" + }, + "typical": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", + "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==" + } + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "core-js-pure": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.36.1.tgz", + "integrity": "sha512-NXCvHvSVYSrewP0L5OhltzXeWFJLo2AL2TYnj6iLV3Bw8mM62wAQMNgUCRI6EBu6hVVpbCxmOPlxh1Ikw2PfUA==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cosmiconfig": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "dev": true, "requires": { - "lodash.assignwith": "^4.2.0", - "typical": "^7.1.1" + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, "dependencies": { - "typical": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", - "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==" + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } } } }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "create-eslint-index": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/create-eslint-index/-/create-eslint-index-1.0.0.tgz", + "integrity": "sha512-nXvJjnfDytOOaPOonX0h0a1ggMoqrhdekGeZkD6hkcWYvlCWhU719tKFVh8eU04CnMwu3uwe1JjwuUF2C3k2qg==", + "dev": true, "requires": { - "@jridgewell/trace-mapping": "0.3.9" + "lodash.get": "^4.3.0" } }, - "@glideapps/ts-necessities": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.1.3.tgz", - "integrity": "sha512-q9U8v/n9qbkd2zDYjuX3qtlbl+OIyI9zF+zQhZjfYOE9VMDH7tfcUSJ9p0lXoY3lxmGFne09yi4iiNeQUwV7AA==" + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "requires": { + "node-fetch": "^2.6.12" + } }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" } }, - "@mark.probst/typescript-json-schema": { - "version": "0.55.0", - "resolved": "https://registry.npmjs.org/@mark.probst/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", - "integrity": "sha512-jI48mSnRgFQxXiE/UTUCVCpX8lK3wCFKLF1Ss2aEreboKNuLQGt3e0/YFqWVHe/WENxOaqiJvwOz+L/SrN2+qQ==", + "data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, "requires": { - "@types/json-schema": "^7.0.9", - "@types/node": "^16.9.2", - "glob": "^7.1.7", - "path-equal": "^1.1.2", - "safe-stable-stringify": "^2.2.0", - "ts-node": "^10.9.1", - "typescript": "4.9.4", - "yargs": "^17.1.1" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "dataloader": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", + "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-equal": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", + "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.1", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" }, "dependencies": { - "@types/node": { - "version": "16.18.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", - "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==" - }, - "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true } } }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } }, - "@tsconfig/node18": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-1.0.1.tgz", - "integrity": "sha512-sNFeK6X2ATlhlvzyH4kKYQlfHXE2f2/wxtB9ClvYXevWpmwkUT7VaSrjIN9E76Qebz8qP5JOJJ9jD3QoD/Z9TA==", + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true }, - "@types/browser-or-node": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/browser-or-node/-/browser-or-node-1.3.2.tgz", - "integrity": "sha512-CkvJrvVMI4ZHbiL+Df22Owzq1IYnHnoSrM8s6Dmy4MRdqvdFi9bHsIvyFrSGJPOxvFI9Y3MqY2gFCqIafJBcfw==", - "dev": true + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, - "@types/command-line-args": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz", - "integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==", + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dset": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", + "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", "dev": true }, - "@types/command-line-usage": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", - "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==", + "electron-to-chromium": { + "version": "1.4.717", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz", + "integrity": "sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==", "dev": true }, - "@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "enhance-visitors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/enhance-visitors/-/enhance-visitors-1.0.0.tgz", + "integrity": "sha512-+29eJLiUixTEDRaZ35Vu8jP3gPLNcQQkQkOQjLp2X+6cZGGPDD/uasbFzvLsJKnGZnvmyZ0srxudwOtskHeIDA==", "dev": true, "requires": { - "@types/minimatch": "*", - "@types/node": "*" + "lodash": "^4.13.1" } }, - "@types/graphql": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.11.8.tgz", - "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", - "dev": true + "enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } }, - "@types/js-base64": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/js-base64/-/js-base64-3.3.1.tgz", - "integrity": "sha512-Zw33oQNAvDdAN9b0IE5stH0y2MylYvtU7VVTKEJPxhyM2q57CVaNJhtJW258ah24NRtaiA23tptUmVn3dmTKpw==", + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { - "js-base64": "*" + "is-arrayish": "^0.2.1" } }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + "es-abstract": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", + "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.5", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + } + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + } }, - "@types/lodash": { - "version": "4.14.197", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.197.tgz", - "integrity": "sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==", + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } }, - "@types/node": { - "version": "18.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", - "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==" + "es-iterator-helpers": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + } }, - "@types/pako": { + "es-object-atoms": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.0.tgz", - "integrity": "sha1-6q6DZNG391LiY7w/1o3+yY5hNsU=", - "dev": true - }, - "@types/pluralize": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.30.tgz", - "integrity": "sha512-kVww6xZrW/db5BR9OqiT71J9huRdQ+z/r+LbDuT7/EK50mCmj5FoaIARnVv0rvjUS/YpDox0cDU9lpQT011VBA==", - "dev": true - }, - "@types/readable-stream": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.10.tgz", - "integrity": "sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, "requires": { - "@types/node": "*", - "safe-buffer": "~5.1.1" + "es-errors": "^1.3.0" } }, - "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "@types/shelljs": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.12.tgz", - "integrity": "sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==", + "es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "requires": { - "@types/glob": "~7.2.0", - "@types/node": "*" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" } }, - "@types/stream-chain": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stream-chain/-/stream-chain-2.0.1.tgz", - "integrity": "sha512-D+Id9XpcBpampptkegH7WMsEk6fUdf9LlCIX7UhLydILsqDin4L0QT7ryJR0oycwC7OqohIzdfcMHVZ34ezNGg==", + "es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "requires": { - "@types/node": "*" + "hasown": "^2.0.0" } }, - "@types/stream-json": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@types/stream-json/-/stream-json-1.7.3.tgz", - "integrity": "sha512-Jqsyq5VPOTWorvEmzWhEWH5tJnHA+bB8vt/Zzb11vSDj8esfSHDMj2rbVjP0mfJQzl3YBJSXBBq08iiyaBK3KA==", + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { - "@types/node": "*", - "@types/stream-chain": "*" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, - "@types/unicode-properties": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/unicode-properties/-/unicode-properties-1.3.0.tgz", - "integrity": "sha512-kDVlxpdkCfgvzfXcglkr7j4OSMjCEEo/Jloj4tFuldYZpQ9Uypy7FGXPhNstoj4eGvhddwuu5n0EfI+XdWVoVA==", - "dev": true + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, - "@types/urijs": { - "version": "1.19.25", - "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", - "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==" + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true }, - "@types/yaml": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", - "integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==", + "eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "requires": { - "yaml": "*" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } } }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "eslint-ast-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-ast-utils/-/eslint-ast-utils-1.1.0.tgz", + "integrity": "sha512-otzzTim2/1+lVrlH19EfQQJEhVJSu0zOb9ygb3iapN6UlyaDtyRq4b5U1FuW0v1lRa9Fp/GJyHkSwm6NqABgCA==", + "dev": true, "requires": { - "event-target-shim": "^5.0.0" + "lodash.get": "^4.4.2", + "lodash.zip": "^4.2.0" } }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "eslint-compat-utils": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz", + "integrity": "sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==", "dev": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "semver": "^7.5.4" } }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "eslint-config-canonical": { + "version": "41.4.2", + "resolved": "https://registry.npmjs.org/eslint-config-canonical/-/eslint-config-canonical-41.4.2.tgz", + "integrity": "sha512-ayP7OPe7Mh0Vf1K8PXQshekyeM3dNcEVwoJAu5ozrZXftaY36NPaH57Oj1FcmMzr2gpc3WbjQ5frVqxnqjnKMg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "@babel/core": "^7.23.0", + "@babel/eslint-parser": "^7.22.15", + "@babel/eslint-plugin": "^7.22.10", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@graphql-eslint/eslint-plugin": "^3.20.1", + "@next/eslint-plugin-next": "^13.5.4", + "@rushstack/eslint-patch": "^1.5.1", + "@typescript-eslint/eslint-plugin": "^6.7.5", + "@typescript-eslint/parser": "^6.7.5", + "eslint-config-prettier": "^9.0.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-ava": "^14.0.0", + "eslint-plugin-canonical": "^4.14.0", + "eslint-plugin-cypress": "^2.15.1", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-fp": "^2.3.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jest": "^27.4.2", + "eslint-plugin-jsdoc": "^46.8.2", + "eslint-plugin-jsonc": "^2.10.0", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-lodash": "^7.4.0", + "eslint-plugin-mocha": "^10.2.0", + "eslint-plugin-modules-newline": "0.0.6", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-regexp": "^1.15.0", + "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-typescript-sort-keys": "^3.0.0", + "eslint-plugin-unicorn": "^48.0.1", + "eslint-plugin-vitest": "^0.3.2", + "eslint-plugin-yml": "^1.10.0", + "eslint-plugin-zod": "^1.4.0", + "prettier": "^3.0.3", + "ramda": "^0.29.1", + "yaml-eslint-parser": "^1.2.2" + }, + "dependencies": { + "eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "requires": {} + }, + "eslint-plugin-canonical": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-canonical/-/eslint-plugin-canonical-4.18.0.tgz", + "integrity": "sha512-0Egc0FKOnCRdu3bFEJhfHkdkusIgW0UxdemukkowZQnQsnf12FHSJ7K26b+tZ5pKB7cTyECSaqvEpoIJfplX4g==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "^6.1.0", + "chance": "^1.1.11", + "debug": "^4.3.4", + "eslint-import-resolver-typescript": "^3.5.3", + "eslint-module-utils": "^2.7.4", + "is-get-set-prop": "^1.0.0", + "is-js-type": "^2.0.0", + "is-obj-prop": "^1.0.0", + "is-proto-prop": "^2.0.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "recast": "^0.23.2", + "roarr": "^7.14.2", + "ts-unused-exports": "^9.0.3", + "xregexp": "^5.1.1" + } + }, + "eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + } + }, + "synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "requires": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } } }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + "eslint-config-prettier": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", + "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, - "array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + "eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + } }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true + "eslint-plugin-ava": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-ava/-/eslint-plugin-ava-14.0.0.tgz", + "integrity": "sha512-XmKT6hppaipwwnLVwwvQliSU6AF1QMHiNoLD5JQfzhUhf0jY7CO0O624fQrE+Y/fTb9vbW8r77nKf7M/oHulxw==", + "dev": true, + "requires": { + "enhance-visitors": "^1.0.0", + "eslint-utils": "^3.0.0", + "espree": "^9.0.0", + "espurify": "^2.1.1", + "import-modules": "^2.1.0", + "micro-spelling-correcter": "^1.1.1", + "pkg-dir": "^5.0.0", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "eslint-plugin-canonical": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-canonical/-/eslint-plugin-canonical-3.4.0.tgz", + "integrity": "sha512-akY2RpJD3VC2XXsU/02VsbzkHfybsZTsruOKPI7pJzQ+lZaS3UGM1H0vUKf0itXsbMHHJbIT78hUXU2d2HemZQ==", + "dev": true, + "requires": { + "is-get-set-prop": "^1.0.0", + "is-js-type": "^2.0.0", + "is-obj-prop": "^1.0.0", + "is-proto-prop": "^2.0.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "ts-unused-exports": "^9.0.3", + "xregexp": "^5.1.1" + } }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "eslint-plugin-cypress": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz", + "integrity": "sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w==", + "dev": true, + "requires": { + "globals": "^13.20.0" + } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, - "browser-or-node": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", - "integrity": "sha512-sVIA0cysIED0nbmNOm7sZzKfgN1rpFmrqvLZaFWspaBAftfQcezlC81G6j6U2RJf4Lh66zFxrCeOsvkUXIcPWg==" + "eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + } }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "dev": true, "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "eslint-plugin-fp": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-fp/-/eslint-plugin-fp-2.3.0.tgz", + "integrity": "sha512-3n2oHibwoIxAht9/+ZaTldhI6brXORgl8oNXqZd+d9xuAQt2SBJ2/aml0oQRMWvXrgsz2WG6wfC++NjzSG3prA==", + "dev": true, + "requires": { + "create-eslint-index": "^1.0.0", + "eslint-ast-utils": "^1.0.0", + "lodash": "^4.13.1", + "req-all": "^0.1.0" + } }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "eslint-plugin-jest": { + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", + "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@typescript-eslint/utils": "^5.10.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, "requires": { - "color-convert": "^2.0.1" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, "requires": { - "color-name": "~1.1.4" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, "requires": { - "has-flag": "^4.0.0" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" } } } }, - "chalk-template": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", - "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "eslint-plugin-jsdoc": { + "version": "46.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", + "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", + "dev": true, "requires": { - "chalk": "^4.1.2" + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + } } }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "eslint-plugin-json": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-3.1.0.tgz", + "integrity": "sha512-MrlG2ynFEHe7wDGwbUuFPsaT2b1uhuEFhJ+W1f1u+1C2EkXmTYJp4B1aAdQQ8M+CC3t//N/oRKiIVw14L2HR1g==", + "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "lodash": "^4.17.21", + "vscode-json-languageservice": "^4.1.6" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "collection-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", - "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==" + "eslint-plugin-jsonc": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.14.1.tgz", + "integrity": "sha512-Tei6G4N7pZulP5MHi0EIdtseiCqUPkDMd0O8Zrw4muMIlsjJ5/B9X+U3Pfo6B7l0mTL9LN9FwuWT70dRJ6z7tg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "eslint-compat-utils": "^0.5.0", + "espree": "^9.6.1", + "graphemer": "^1.4.0", + "jsonc-eslint-parser": "^2.0.4", + "natural-compare": "^1.4.0", + "synckit": "^0.6.0" + } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", "dev": true, "requires": { - "color-name": "1.1.3" + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" }, "dependencies": { - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true } } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "eslint-plugin-lodash": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-lodash/-/eslint-plugin-lodash-7.4.0.tgz", + "integrity": "sha512-Tl83UwVXqe1OVeBRKUeWcfg6/pCW1GTRObbdnbEJgYwjxp5Q92MEWQaH9+dmzbRt6kvYU1Mp893E79nJiCSM8A==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } }, - "command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "eslint-plugin-mocha": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.1.tgz", + "integrity": "sha512-G85ALUgKaLzuEuHhoW3HVRgPTmia6njQC3qCG6CEvA8/Ja9PDZnRZOuzekMki+HaViEQXINuYsmhp5WR5/4MfA==", + "dev": true, "requires": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" + "eslint-utils": "^3.0.0", + "globals": "^13.24.0", + "rambda": "^7.4.0" } }, - "command-line-usage": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", - "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", + "eslint-plugin-modules-newline": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-modules-newline/-/eslint-plugin-modules-newline-0.0.6.tgz", + "integrity": "sha512-69NpBr68U6pmXL+y+KHl/64PwRarceC3/sCNUVxRbe0gPI32SIw8AtdpkqNiJYCa2yMd4lRrkrnU09Yio7KVzA==", + "dev": true, "requires": { - "array-back": "^6.2.2", - "chalk-template": "^0.4.0", - "table-layout": "^3.0.0", - "typical": "^7.1.1" + "requireindex": "~1.1.0" + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "dependencies": { - "array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==" + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } }, - "typical": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.1.1.tgz", - "integrity": "sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==" + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true } } }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "requires": {} }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "dev": true, + "requires": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + "eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "requires": {} }, - "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "eslint-plugin-regexp": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-1.15.0.tgz", + "integrity": "sha512-YEtQPfdudafU7RBIFci81R/Q1yErm0mVh3BkGnXD2Dk8DLwTFdc2ITYH1wCnHKim2gnHfPFgrkh+b2ozyyU7ag==", + "dev": true, "requires": { - "node-fetch": "^2.6.12" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "comment-parser": "^1.1.2", + "grapheme-splitter": "^1.0.4", + "jsdoctypeparser": "^9.0.0", + "refa": "^0.11.0", + "regexp-ast-analysis": "^0.6.0", + "scslre": "^0.2.0" } }, - "deep-equal": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", - "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "requires": {} + }, + "eslint-plugin-typescript-sort-keys": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-typescript-sort-keys/-/eslint-plugin-typescript-sort-keys-3.2.0.tgz", + "integrity": "sha512-GutszvriaVtwmn7pQjuj9/9o0iXhD7XZs0/424+zsozdRr/fdg5e8206t478Vnqnqi1GjuxcAolj1kf74KnhPA==", "dev": true, "requires": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.1", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "@typescript-eslint/experimental-utils": "^5.0.0", + "json-schema": "^0.4.0", + "natural-compare-lite": "^1.4.0" + } + }, + "eslint-plugin-unicorn": { + "version": "48.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-48.0.1.tgz", + "integrity": "sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "@eslint-community/eslint-utils": "^4.4.0", + "ci-info": "^3.8.0", + "clean-regexp": "^1.0.0", + "esquery": "^1.5.0", + "indent-string": "^4.0.0", + "is-builtin-module": "^3.2.1", + "jsesc": "^3.0.2", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "read-pkg-up": "^7.0.1", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.10.0", + "semver": "^7.5.4", + "strip-indent": "^3.0.0" }, "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true + }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true + } + } + }, + "eslint-plugin-vitest": { + "version": "0.3.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.3.26.tgz", + "integrity": "sha512-oxe5JSPgRjco8caVLTh7Ti8PxpwJdhSV0hTQAmkFcNcmy/9DnqLB/oNVRA11RmVRP//2+jIIT6JuBEcpW3obYg==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "^7.1.1" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" + } + }, + "@typescript-eslint/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "semver": "^7.5.4" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.4.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } } } }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "eslint-plugin-yml": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-1.13.2.tgz", + "integrity": "sha512-1i71VhmsG5UxE41rIJmJjhlTTxYy7upAY5Hqj8AdBc7rfJzRIZr3a2spuOS8+N7ZDCWsHAWY3J6lzQNQHDv6Uw==", "dev": true, "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "debug": "^4.3.2", + "eslint-compat-utils": "^0.5.0", + "lodash": "^4.17.21", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^1.2.1" } }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + "eslint-plugin-zod": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-zod/-/eslint-plugin-zod-1.4.0.tgz", + "integrity": "sha512-i9WzQGw2X5fQcuQh33mA8DQjZJM/yuyZvs1Fc5EyTidX7Ed/g832+1FEQ4u5gtXy+jZ+DVsB5+oMHj4tIOfeZg==", + "dev": true, + "requires": {} }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true }, - "encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, "requires": { - "iconv-lite": "^0.6.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, - "es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "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 + }, + "espurify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/espurify/-/espurify-2.1.1.tgz", + "integrity": "sha512-zttWvnkhcDyGOhSH4vO2qCBILpdCMv/MX8lp4cqgRkQoDRGK2oZxi2GfWhlP2dIXmk7BaKeOTuzbHhyC68o8XQ==", + "dev": true + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -3141,18 +12424,128 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, + "extract-files": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz", + "integrity": "sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==", + "dev": true + }, + "fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "dev": true + }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", "dev": true }, + "fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-printf": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", + "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", + "dev": true, + "requires": { + "boolean": "^3.1.4" + } + }, + "fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dev": true, + "requires": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dev": true, + "requires": { + "punycode": "^1.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + } + } + }, + "fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-replace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", @@ -3161,6 +12554,33 @@ "array-back": "^3.0.1" } }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3176,32 +12596,83 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-set-props": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-set-props/-/get-set-props-0.1.0.tgz", + "integrity": "sha512-7oKuKzAGKj0ag+eWZwcGw2fjiZ78tXnXQoBgY0aU7ZOxTu4bB7hSuQSDgtKy978EDH062P5FmD2EWiDpQS9K9Q==", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + } + }, + "get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" } }, "glob": { @@ -3217,6 +12688,47 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -3226,6 +12738,24 @@ "get-intrinsic": "^1.1.3" } }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "graphql": { "version": "0.11.7", "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.11.7.tgz", @@ -3234,15 +12764,303 @@ "iterall": "1.1.3" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "graphql-config": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-4.5.0.tgz", + "integrity": "sha512-x6D0/cftpLUJ0Ch1e5sj1TZn6Wcxx4oMfmhaG9shM0DKajA9iR+j1z86GSTQ19fShbGvrSSvbIQsHku6aQ6BBw==", + "dev": true, + "requires": { + "@graphql-tools/graphql-file-loader": "^7.3.7", + "@graphql-tools/json-file-loader": "^7.3.7", + "@graphql-tools/load": "^7.5.5", + "@graphql-tools/merge": "^8.2.6", + "@graphql-tools/url-loader": "^7.9.7", + "@graphql-tools/utils": "^9.0.0", + "cosmiconfig": "8.0.0", + "jiti": "1.17.1", + "minimatch": "4.2.3", + "string-env-interpolation": "1.0.1", + "tslib": "^2.4.0" + }, + "dependencies": { + "@graphql-tools/graphql-file-loader": { + "version": "7.5.17", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.5.17.tgz", + "integrity": "sha512-hVwwxPf41zOYgm4gdaZILCYnKB9Zap7Ys9OhY1hbwuAuC4MMNY9GpUjoTU3CQc3zUiPoYStyRtUGkHSJZ3HxBw==", + "dev": true, + "requires": { + "@graphql-tools/import": "6.7.18", + "@graphql-tools/utils": "^9.2.1", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "dependencies": { + "@graphql-tools/import": { + "version": "6.7.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-6.7.18.tgz", + "integrity": "sha512-XQDdyZTp+FYmT7as3xRWH/x8dx0QZA2WZqfMF5EWb36a0PiH7WwlRQYIdyYXj8YCLpiWkeBXgBRHmMnwEYR8iQ==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "resolve-from": "5.0.0", + "tslib": "^2.4.0" + } + } + } + }, + "@graphql-tools/json-file-loader": { + "version": "7.4.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-7.4.18.tgz", + "integrity": "sha512-AJ1b6Y1wiVgkwsxT5dELXhIVUPs/u3VZ8/0/oOtpcoyO/vAeM5rOvvWegzicOOnQw8G45fgBRMkkRfeuwVt6+w==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + } + }, + "@graphql-tools/load": { + "version": "7.8.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-7.8.14.tgz", + "integrity": "sha512-ASQvP+snHMYm+FhIaLxxFgVdRaM0vrN9wW2BKInQpktwWTXVyk+yP5nQUCEGmn0RTdlPKrffBaigxepkEAJPrg==", + "dev": true, + "requires": { + "@graphql-tools/schema": "^9.0.18", + "@graphql-tools/utils": "^9.2.1", + "p-limit": "3.1.0", + "tslib": "^2.4.0" + }, + "dependencies": { + "@graphql-tools/schema": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", + "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "dev": true, + "requires": { + "@graphql-tools/merge": "^8.4.1", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + } + } + } + }, + "@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + } + }, + "@graphql-tools/url-loader": { + "version": "7.17.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-7.17.18.tgz", + "integrity": "sha512-ear0CiyTj04jCVAxi7TvgbnGDIN2HgqzXzwsfcqiVg9cvjT40NcMlZ2P1lZDgqMkZ9oyLTV8Bw6j+SyG6A+xPw==", + "dev": true, + "requires": { + "@ardatan/sync-fetch": "^0.0.1", + "@graphql-tools/delegate": "^9.0.31", + "@graphql-tools/executor-graphql-ws": "^0.0.14", + "@graphql-tools/executor-http": "^0.1.7", + "@graphql-tools/executor-legacy-ws": "^0.0.11", + "@graphql-tools/utils": "^9.2.1", + "@graphql-tools/wrap": "^9.4.2", + "@types/ws": "^8.0.0", + "@whatwg-node/fetch": "^0.8.0", + "isomorphic-ws": "^5.0.0", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.11", + "ws": "^8.12.0" + }, + "dependencies": { + "@graphql-tools/delegate": { + "version": "9.0.35", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-9.0.35.tgz", + "integrity": "sha512-jwPu8NJbzRRMqi4Vp/5QX1vIUeUPpWmlQpOkXQD2r1X45YsVceyUUBnktCrlJlDB4jPRVy7JQGwmYo3KFiOBMA==", + "dev": true, + "requires": { + "@graphql-tools/batch-execute": "^8.5.22", + "@graphql-tools/executor": "^0.0.20", + "@graphql-tools/schema": "^9.0.19", + "@graphql-tools/utils": "^9.2.1", + "dataloader": "^2.2.2", + "tslib": "^2.5.0", + "value-or-promise": "^1.0.12" + }, + "dependencies": { + "@graphql-tools/batch-execute": { + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.5.22.tgz", + "integrity": "sha512-hcV1JaY6NJQFQEwCKrYhpfLK8frSXDbtNMoTur98u10Cmecy1zrqNKSqhEyGetpgHxaJRqszGzKeI3RuroDN6A==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "dataloader": "^2.2.2", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + } + }, + "@graphql-tools/executor": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-0.0.20.tgz", + "integrity": "sha512-GdvNc4vszmfeGvUqlcaH1FjBoguvMYzxAfT6tDd4/LgwymepHhinqLNA5otqwVLW+JETcDaK7xGENzFomuE6TA==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "@graphql-typed-document-node/core": "3.2.0", + "@repeaterjs/repeater": "^3.0.4", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + } + }, + "@graphql-tools/schema": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", + "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "dev": true, + "requires": { + "@graphql-tools/merge": "^8.4.1", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + } + } + } + }, + "@graphql-tools/executor-graphql-ws": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-0.0.14.tgz", + "integrity": "sha512-P2nlkAsPZKLIXImFhj0YTtny5NQVGSsKnhi7PzXiaHSXc6KkzqbWZHKvikD4PObanqg+7IO58rKFpGXP7eeO+w==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "@repeaterjs/repeater": "3.0.4", + "@types/ws": "^8.0.0", + "graphql-ws": "5.12.1", + "isomorphic-ws": "5.0.0", + "tslib": "^2.4.0", + "ws": "8.13.0" + } + }, + "@graphql-tools/executor-http": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-0.1.10.tgz", + "integrity": "sha512-hnAfbKv0/lb9s31LhWzawQ5hghBfHS+gYWtqxME6Rl0Aufq9GltiiLBcl7OVVOnkLF0KhwgbYP1mB5VKmgTGpg==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "@repeaterjs/repeater": "^3.0.4", + "@whatwg-node/fetch": "^0.8.1", + "dset": "^3.1.2", + "extract-files": "^11.0.0", + "meros": "^1.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + } + }, + "@graphql-tools/executor-legacy-ws": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-0.0.11.tgz", + "integrity": "sha512-4ai+NnxlNfvIQ4c70hWFvOZlSUN8lt7yc+ZsrwtNFbFPH/EroIzFMapAxM9zwyv9bH38AdO3TQxZ5zNxgBdvUw==", + "dev": true, + "requires": { + "@graphql-tools/utils": "^9.2.1", + "@types/ws": "^8.0.0", + "isomorphic-ws": "5.0.0", + "tslib": "^2.4.0", + "ws": "8.13.0" + } + }, + "@graphql-tools/wrap": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-9.4.2.tgz", + "integrity": "sha512-DFcd9r51lmcEKn0JW43CWkkI2D6T9XI1juW/Yo86i04v43O9w2/k4/nx2XTJv4Yv+iXwUw7Ok81PGltwGJSDSA==", + "dev": true, + "requires": { + "@graphql-tools/delegate": "^9.0.31", + "@graphql-tools/schema": "^9.0.18", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "dependencies": { + "@graphql-tools/schema": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", + "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "dev": true, + "requires": { + "@graphql-tools/merge": "^8.4.1", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + } + } + } + } + } + }, + "@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "dev": true, + "requires": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + } + }, + "minimatch": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.3.tgz", + "integrity": "sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "requires": {} + } + } + }, + "graphql-depth-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/graphql-depth-limit/-/graphql-depth-limit-1.1.0.tgz", + "integrity": "sha512-+3B2BaG8qQ8E18kzk9yiSdAa75i/hnnOwgSeAxVJctGQPvmeiLtqKOYF6HETCyRjiF7Xfsyal0HbLlxCQkgkrw==", "dev": true, "requires": { - "function-bind": "^1.1.1" + "arrify": "^1.0.1" } }, + "graphql-ws": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.12.1.tgz", + "integrity": "sha512-umt4f5NnMK46ChM2coO36PTFhHouBrK9stWWBczERguwYrGnPNxJ9dimU6IyOBfOkC6Izhkg4H8+F51W/8CYDg==", + "dev": true, + "requires": {} + }, "has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -3256,18 +13074,18 @@ "dev": true }, "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "requires": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" } }, "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true }, "has-symbols": { @@ -3277,14 +13095,29 @@ "dev": true }, "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "function-bind": "^1.1.2" } }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -3298,6 +13131,40 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, + "ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-modules": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-modules/-/import-modules-2.1.0.tgz", + "integrity": "sha512-8HEWcnkbGpovH9yInoisxaSoIg9Brbul+Ju3Kqe2UsYDUBJD/iQjSgEj0zPcTDPKfPp2fs5xlv1i+JSye/m1/A==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3313,13 +13180,13 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" } }, @@ -3340,14 +13207,28 @@ } }, "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, "requires": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.1" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" } }, "is-bigint": { @@ -3369,12 +13250,47 @@ "has-tostringtag": "^1.0.0" } }, + "is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + }, + "dependencies": { + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + } + } + }, "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "requires": { + "is-typed-array": "^1.1.13" + } + }, "is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -3384,17 +13300,81 @@ "has-tostringtag": "^1.0.0" } }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-get-set-prop": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-get-set-prop/-/is-get-set-prop-1.0.0.tgz", + "integrity": "sha512-DvAYZ1ZgGUz4lzxKMPYlt08qAUqyG9ckSg2pIjfvcQ7+pkVNUHk8yVLXOnCLe5WKXhLop8oorWFBJHpwWQpszQ==", + "dev": true, + "requires": { + "get-set-props": "^0.1.0", + "lowercase-keys": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-js-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-js-type/-/is-js-type-2.0.0.tgz", + "integrity": "sha512-Aj13l47+uyTjlQNHtXBV8Cji3jb037vxwMWCgopRR8h6xocgBGW3qG8qGlIOEmbXQtkKShKuBM9e8AA1OeQ+xw==", + "dev": true, + "requires": { + "js-types": "^1.0.0" + } + }, "is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "dev": true }, + "is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-number-object": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", @@ -3404,6 +13384,32 @@ "has-tostringtag": "^1.0.0" } }, + "is-obj-prop": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-obj-prop/-/is-obj-prop-1.0.0.tgz", + "integrity": "sha512-5Idb61slRlJlsAzi0Wsfwbp+zZY+9LXKUAZpvT/1ySw+NxKLRWfa0Bzj+wXI3fX5O9hiddm5c3DAaRSNP/yl2w==", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0", + "obj-props": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-proto-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-2.0.0.tgz", + "integrity": "sha512-jl3NbQ/fGLv5Jhan4uX+Ge9ohnemqyblWVVCpAvtTQzNFvV2xhJq+esnkIbYQ9F1nITXoLfDDQLp7LBw/zzncg==", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0", + "proto-props": "^2.0.0" + } + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3421,12 +13427,12 @@ "dev": true }, "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, "requires": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" } }, "is-stream": { @@ -3453,16 +13459,12 @@ } }, "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.14" } }, "is-url": { @@ -3476,6 +13478,15 @@ "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", "dev": true }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-weakset": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", @@ -3491,16 +13502,60 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "dev": true, + "requires": {} + }, "iterall": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz", "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==" }, + "iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "requires": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "jiti": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.17.1.tgz", + "integrity": "sha512-NZIITw8uZQFuzQimqjUxIrIcEdxYDFIe/0xYfIlVXTkiBjjyBEvgasj5bb0/cHtPRD/NziPbT312sFrkI5ALpw==", + "dev": true + }, "js-base64": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-types": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/js-types/-/js-types-1.0.0.tgz", + "integrity": "sha512-bfwqBW9cC/Lp7xcRpug7YrXm0IVw+T9e3g4mCYnv0Pjr3zIzU9PCQElYU9oSGAWzXlbdl9X5SAMPejO9sxkeUw==", + "dev": true + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -3509,22 +13564,141 @@ "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" - }, - "dependencies": { - "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 - } } }, + "jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true + }, + "jsdoctypeparser": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz", + "integrity": "sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonc-eslint-parser": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz", + "integrity": "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==", + "dev": true, + "requires": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" + } + }, + "jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "requires": { + "language-subtag-registry": "^0.3.20" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -3540,6 +13714,45 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "lodash.lowercase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.lowercase/-/lodash.lowercase-4.3.0.tgz", + "integrity": "sha512-UcvP1IZYyDKyEL64mmrwoA1AbFu5ahojhTtkOUr1K9dbuxzS9ev8i4TxMMGCqRC9TE8uDaSoufNAXxRPNTseVA==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3560,6 +13773,41 @@ "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "meros": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.0.tgz", + "integrity": "sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==", + "dev": true, + "requires": {} + }, + "micro-spelling-correcter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/micro-spelling-correcter/-/micro-spelling-correcter-1.1.1.tgz", + "integrity": "sha512-lkJ3Rj/mtjlRcHk6YyCbvZhyWTOzdBvTHsxMmZSk5jxN1YyVSQ+JETAom55mdzfcyDrY/49Z7UCW760BK30crg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3588,6 +13836,24 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node-fetch": { "version": "2.6.12", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", @@ -3596,10 +13862,57 @@ "whatwg-url": "^5.0.0" } }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "obj-props": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/obj-props/-/obj-props-1.4.0.tgz", + "integrity": "sha512-p7p/7ltzPDiBs6DqxOrIbtRdwxxVRBj5ROukeNb9RgA+fawhrz5n2hpNz8DDmYR//tviJSj7nUnlppGmONkjiQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true }, "object-is": { @@ -3619,17 +13932,73 @@ "dev": true }, "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, + "object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, + "object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + } + }, + "object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + } + }, + "object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "requires": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + } + }, + "object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3638,38 +14007,157 @@ "wrappy": "1" } }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "pako": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, "path-equal": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==" }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "requires": { + "find-up": "^5.0.0" + } + }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" }, + "possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, "prettier": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz", - "integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -3686,6 +14174,58 @@ "integrity": "sha512-5yANTE0tmi5++POym6OgtFmwfDvOXABD9oj/jLQr5GPEyuNEb7jH4wbbANJceJid49jwhi1RddxnhnEAb/doqg==", "dev": true }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "proto-props": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proto-props/-/proto-props-2.0.0.tgz", + "integrity": "sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==", + "dev": true + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "pvtsutils": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", + "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", + "dev": true, + "requires": { + "tslib": "^2.6.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "quicktype-core": { "version": "file:packages/quicktype-core", "requires": { @@ -3820,6 +14360,100 @@ } } }, + "rambda": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", + "integrity": "sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==", + "dev": true + }, + "ramda": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", + "integrity": "sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA==", + "dev": true + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, "readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", @@ -3847,6 +14481,27 @@ } } }, + "recast": { + "version": "0.23.6", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.6.tgz", + "integrity": "sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==", + "dev": true, + "requires": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -3856,29 +14511,186 @@ "resolve": "^1.1.6" } }, + "refa": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.11.0.tgz", + "integrity": "sha512-486O8/pQXwj9jV0mVvUnTsxq0uknpBnNJ0eCUhkZqJRQ8KutrT1PhzmumdCeM1hSBF2eMlFPmwECRER4IbKXlQ==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.0" + } + }, + "reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + } + }, + "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 + }, + "regexp-ast-analysis": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.6.0.tgz", + "integrity": "sha512-OLxjyjPkVH+rQlBLb1I/P/VTmamSjGkvN5PTV5BXP432k3uVz727J7H29GA5IFiY0m7e1xBN7049Wn59FY3DEQ==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.0", + "refa": "^0.11.0" + } + }, + "regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true + }, "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regjsparser": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz", + "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } } }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true + }, + "req-all": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/req-all/-/req-all-0.1.0.tgz", + "integrity": "sha512-ZdvPr8uXy9ujX3KujwE2P1HWkMYgogIhqeAeyb47MqWjSfyxERSm0TNbN/IapCCmWDufXab04AYrRgObaJCJ6Q==", + "dev": true + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, + "requireindex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", + "integrity": "sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==", + "dev": true + }, "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "roarr": { + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-7.21.1.tgz", + "integrity": "sha512-3niqt5bXFY1InKU8HKWqqYTYjtrBaxBMnXELXCXUYgtNYGUtZM5rB46HIC430AyacL95iEniGf7RgqsesykLmQ==", + "dev": true, + "requires": { + "fast-printf": "^1.6.9", + "safe-stable-stringify": "^2.4.3", + "semver-compare": "^1.0.0" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "queue-microtask": "^1.2.2" + } + }, + "safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } } }, "safe-buffer": { @@ -3886,25 +14698,94 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + } + }, "safe-stable-stringify": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", - "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==" + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==" }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "scslre": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.2.0.tgz", + "integrity": "sha512-4hc49fUMmX3jM0XdFUAPBrs1xwEcdHa0KyjEsjFs+Zfc66mpFpq5YmRgDtl+Ffo6AtJIilfei+yKw8fUn3N88w==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.0", + "refa": "^0.11.0", + "regexp-ast-analysis": "^0.6.0" + } + }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "lru-cache": "^6.0.0" + } + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" } }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "shelljs": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", @@ -3917,16 +14798,73 @@ } }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + }, + "dependencies": { + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + } + } + }, + "spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, + "spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3960,6 +14898,12 @@ "resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz", "integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==" }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -3968,6 +14912,18 @@ "safe-buffer": "~5.1.0" } }, + "string-env-interpolation": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz", + "integrity": "sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==", + "dev": true + }, + "string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "dev": true + }, "string-to-stream": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-3.0.1.tgz", @@ -3998,6 +14954,60 @@ "strip-ansi": "^6.0.1" } }, + "string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + } + }, + "string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4006,6 +15016,27 @@ "ansi-regex": "^5.0.1" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4015,6 +15046,29 @@ "has-flag": "^3.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "synckit": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.6.2.tgz", + "integrity": "sha512-Vhf+bUa//YSTYKseDiiEuQmhGCoIF3CVBhunm3r/DQnYiGT4JssmnKQc44BIyOZRK2pKjXXAgbhfmbeoC9CJpA==", + "dev": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "table-layout": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz", @@ -4041,16 +15095,56 @@ } } }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "tiny-inflate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.2.tgz", "integrity": "sha1-k9nez/yIBb1X6uQxDwt0Xptvs6c=" }, + "tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, + "ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "requires": {} + }, "ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -4069,12 +15163,38 @@ "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" + } + }, + "ts-unused-exports": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.5.tgz", + "integrity": "sha512-1XAXaH2i4Al/aZO06pWDn9MUgTN0KQi+fvWudiWfHUTHAav45gzrx7Xq6JAsu6+LoMlVoyGvNvZSPW3KTjDncA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "tsconfig-paths": "^3.9.0" + } + }, + "tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" }, "dependencies": { - "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } } } }, @@ -4105,26 +15225,6 @@ "tsutils": "^2.29.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -4136,12 +15236,6 @@ "supports-color": "^5.3.0" } }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -4159,6 +15253,73 @@ "tslib": "^1.8.1" } }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + } + }, "typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", @@ -4169,6 +15330,18 @@ "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, "unicode-properties": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", @@ -4194,11 +15367,45 @@ } } }, + "unixify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", + "integrity": "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==", + "dev": true, + "requires": { + "normalize-path": "^2.1.1" + } + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "urijs": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" }, + "urlpattern-polyfill": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz", + "integrity": "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==", + "dev": true + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4209,6 +15416,71 @@ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + }, + "dependencies": { + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + } + } + }, + "value-or-promise": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", + "integrity": "sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==", + "dev": true + }, + "vscode-json-languageservice": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", + "integrity": "sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA==", + "dev": true, + "requires": { + "jsonc-parser": "^3.0.0", + "vscode-languageserver-textdocument": "^1.0.3", + "vscode-languageserver-types": "^3.16.0", + "vscode-nls": "^5.0.0", + "vscode-uri": "^3.0.3" + } + }, + "vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "dev": true + }, + "vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true + }, + "vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "dev": true + }, + "vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true + }, "watch": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", @@ -4219,6 +15491,33 @@ "minimist": "^1.2.0" } }, + "web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true + }, + "webcrypto-core": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", + "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.8", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -4238,6 +15537,15 @@ "webidl-conversions": "^3.0.0" } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", @@ -4251,6 +15559,34 @@ "is-symbol": "^1.0.3" } }, + "which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "requires": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, "which-collection": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", @@ -4264,17 +15600,16 @@ } }, "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.2" } }, "wordwrap": { @@ -4320,6 +15655,23 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "peer": true, + "requires": {} + }, + "xregexp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.1.tgz", + "integrity": "sha512-fKXeVorD+CzWvFs7VBuKTYIW63YD1e1osxwQ8caZ6o1jg6pDAbABDG54LCIq0j5cy7PjRvGIq6sef9DYPXpncg==", + "dev": true, + "requires": { + "@babel/runtime-corejs3": "^7.16.5" + } + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -4336,6 +15688,17 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==" }, + "yaml-eslint-parser": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.2.2.tgz", + "integrity": "sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^2.0.0" + } + }, "yargs": { "version": "17.6.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", @@ -4359,6 +15722,12 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index 32092e0c7..7bea464c7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "test": "script/test", "start": "script/watch", "clean": "rm -rf dist node_modules *~ packages/*/{dist,node_modules}", - "debug": "node --inspect-brk --max-old-space-size=4096 ./dist/index.js" + "debug": "node --inspect-brk --max-old-space-size=4096 ./dist/index.js", + "lint": "eslint src/** packages/*/src/**" }, "workspaces": [ "./packages/quicktype-core", @@ -49,8 +50,18 @@ "@types/shelljs": "^0.8.12", "@types/stream-json": "^1.7.3", "@types/urijs": "^1.19.25", + "@typescript-eslint/eslint-plugin": "^6.3.0", + "@typescript-eslint/parser": "^6.3.0", "ajv": "^5.5.2", "deep-equal": "^2.2.2", + "eslint": "^8.57.0", + "eslint-config-canonical": "^41.1.7", + "eslint-config-prettier": "^6.10.0", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-canonical": "^3.4.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-json": "^3.1.0", + "eslint-plugin-prettier": "^4.2.1", "exit": "^0.1.2", "prettier": "^3.0.1", "promise-timeout": "^1.3.0", From b97c2b2bd81b67cdfe26817f486c99303ccd6823 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 7 Apr 2024 08:51:03 -0700 Subject: [PATCH 04/80] add eslint config --- .eslintrc.json | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..922bb451a --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,44 @@ +{ + "overrides": [ + { + "extends": ["canonical/json"], + "files": "*.json" + }, + { + "extends": ["eslint:recommended", "canonical/typescript", "canonical/typescript-type-checking"], + "parserOptions": { + "tsconfigRootDir": "./", + "project": ["./tsconfig.json", "./packages/*/tsconfig.json"] + }, + "plugins": ["canonical"], + "rules": { + "canonical/prefer-inline-type-import": "error", + "@typescript-eslint/consistent-type-definitions": ["error", "interface"], + "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }], + "@typescript-eslint/explicit-function-return-type": "warn", + "@typescript-eslint/indent": ["error", 4], + "@typescript-eslint/quotes": ["error", "double"], + "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], + "@typescript-eslint/naming-convention": "error", + "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/no-unused-vars": ["error", { "vars": "local", "args": "none" }], + "@typescript-eslint/no-use-before-define": "warn", + "@typescript-eslint/no-useless-empty-export": "error", + "@typescript-eslint/prefer-readonly": "warn", + "@typescript-eslint/prefer-reduce-type-parameter": "off", + "@typescript-eslint/switch-exhaustiveness-check": "error", + "@typescript-eslint/unified-signatures": "error" + }, + "overrides": [ + { + "files": "*.d.ts", + "rules": { + "no-var": "off" + } + } + ], + "files": "*.ts" + } + ], + "root": true +} From e504a8a01db8e9e3b1a8a92d629d3542ef85e261 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 7 Apr 2024 08:53:46 -0700 Subject: [PATCH 05/80] remove tslint --- .vscode/tasks.json | 13 - package-lock.json | 225 +----------------- package.json | 1 - packages/quicktype-core/package.json | 4 +- packages/quicktype-core/src/TypeUtils.ts | 2 - packages/quicktype-core/src/input/Inputs.ts | 1 - packages/quicktype-graphql-input/package.json | 6 +- .../src/GraphQLSchema.ts | 2 +- packages/quicktype-graphql-input/src/index.ts | 2 - .../quicktype-typescript-input/package.json | 6 +- src/index.ts | 2 - tslint.json | 67 ------ 12 files changed, 7 insertions(+), 324 deletions(-) delete mode 100644 .vscode/tasks.json delete mode 100644 tslint.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index f36e83f3d..000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "tslint", - "group": "build", - "problemMatcher": ["$tslint5"] - } - ] -} diff --git a/package-lock.json b/package-lock.json index a0ff1b196..6bcb1cc29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,6 @@ "semver": "^7.5.4", "shelljs": "^0.8.5", "ts-node": "^10.9.2", - "tslint": "^6.1.3", "watch": "^1.0.2" }, "engines": { @@ -1861,15 +1860,6 @@ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, - "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/aria-query": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", @@ -2252,15 +2242,6 @@ "ieee754": "^1.2.1" } }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -2519,12 +2500,6 @@ "node": ">=12.17" } }, - "node_modules/commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -6160,19 +6135,6 @@ "node": ">=0.10.0" } }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", @@ -6505,18 +6467,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -7763,12 +7713,6 @@ "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -8222,72 +8166,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "node_modules/tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" - } - }, - "node_modules/tslint/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -8944,7 +8822,6 @@ "@types/readable-stream": "4.0.10", "@types/unicode-properties": "^1.3.0", "@types/yaml": "^1.9.7", - "tslint": "^6.1.3", "typescript": "4.9.5" } }, @@ -8977,7 +8854,6 @@ "devDependencies": { "@types/graphql": "^0.11.7", "@types/node": "18.14.0", - "tslint": "^6.1.3", "typescript": "4.9.5" } }, @@ -8990,8 +8866,7 @@ "typescript": "4.9.5" }, "devDependencies": { - "@types/node": "18.14.0", - "tslint": "^6.1.3" + "@types/node": "18.14.0" } }, "packages/quicktype-typescript-input/node_modules/@glideapps/ts-necessities": { @@ -10444,15 +10319,6 @@ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, "aria-query": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", @@ -10722,12 +10588,6 @@ "ieee754": "^1.2.1" } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -10908,12 +10768,6 @@ } } }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, "comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -13556,16 +13410,6 @@ "integrity": "sha512-bfwqBW9cC/Lp7xcRpug7YrXm0IVw+T9e3g4mCYnv0Pjr3zIzU9PCQElYU9oSGAWzXlbdl9X5SAMPejO9sxkeUw==", "dev": true }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, "jsdoc-type-pratt-parser": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", @@ -13822,15 +13666,6 @@ "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, "moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -14248,7 +14083,6 @@ "pako": "^1.0.6", "pluralize": "^8.0.0", "readable-stream": "4.5.2", - "tslint": "^6.1.3", "typescript": "4.9.5", "unicode-properties": "^1.4.1", "urijs": "^1.19.1", @@ -14281,7 +14115,6 @@ "collection-utils": "^1.0.1", "graphql": "^0.11.7", "quicktype-core": "file:../quicktype-core", - "tslint": "^6.1.3", "typescript": "4.9.5" } }, @@ -14291,7 +14124,6 @@ "@mark.probst/typescript-json-schema": "0.55.0", "@types/node": "18.14.0", "quicktype-core": "file:../quicktype-core", - "tslint": "^6.1.3", "typescript": "4.9.5" }, "dependencies": { @@ -14865,12 +14697,6 @@ "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, "stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -15204,55 +15030,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 7bea464c7..f221ca9ed 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,6 @@ "semver": "^7.5.4", "shelljs": "^0.8.5", "ts-node": "^10.9.2", - "tslint": "^6.1.3", "watch": "^1.0.2" }, "files": [ diff --git a/packages/quicktype-core/package.json b/packages/quicktype-core/package.json index 0550516ff..0cbd4a35b 100644 --- a/packages/quicktype-core/package.json +++ b/packages/quicktype-core/package.json @@ -8,8 +8,7 @@ "repository": "https://github.com/quicktype/quicktype", "scripts": { "clean": "rm -rf dist node_modules *~", - "build": "tsc", - "tslint": "tslint --project ." + "build": "tsc" }, "dependencies": { "@glideapps/ts-necessities": "2.1.3", @@ -37,7 +36,6 @@ "@types/readable-stream": "4.0.10", "@types/unicode-properties": "^1.3.0", "@types/yaml": "^1.9.7", - "tslint": "^6.1.3", "typescript": "4.9.5" }, "files": [ diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index 4f3c57f29..36fb166a9 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -290,7 +290,6 @@ export function matchType( return panic(`Unsupported type ${t.kind} in non-exhaustive match`); } - /* tslint:disable:strict-boolean-expressions */ return matchTypeExhaustive( type, typeNotSupported, @@ -308,7 +307,6 @@ export function matchType( unionType, transformedStringType || typeNotSupported ); - /* tslint:enable */ } export function matchCompoundType( diff --git a/packages/quicktype-core/src/input/Inputs.ts b/packages/quicktype-core/src/input/Inputs.ts index 3baefd9c5..9ff8905fa 100644 --- a/packages/quicktype-core/src/input/Inputs.ts +++ b/packages/quicktype-core/src/input/Inputs.ts @@ -60,7 +60,6 @@ export class JSONInput implements Input> { private readonly _topLevels: Map = new Map(); - /* tslint:disable:no-unused-variable */ constructor(private readonly _compressedJSON: CompressedJSON) {} private addSample(topLevelName: string, sample: Value): void { diff --git a/packages/quicktype-graphql-input/package.json b/packages/quicktype-graphql-input/package.json index ae4b23648..75e96e5bc 100644 --- a/packages/quicktype-graphql-input/package.json +++ b/packages/quicktype-graphql-input/package.json @@ -8,8 +8,7 @@ "repository": "https://github.com/quicktype/quicktype", "scripts": { "clean": "rm -rf dist node_modules *~", - "build": "tsc", - "tslint": "tslint --project ." + "build": "tsc" }, "dependencies": { "quicktype-core": "file:../quicktype-core", @@ -19,8 +18,7 @@ "devDependencies": { "@types/node": "18.14.0", "@types/graphql": "^0.11.7", - "typescript": "4.9.5", - "tslint": "^6.1.3" + "typescript": "4.9.5" }, "files": [ "dist" diff --git a/packages/quicktype-graphql-input/src/GraphQLSchema.ts b/packages/quicktype-graphql-input/src/GraphQLSchema.ts index 5f8d570b9..e53072baf 100644 --- a/packages/quicktype-graphql-input/src/GraphQLSchema.ts +++ b/packages/quicktype-graphql-input/src/GraphQLSchema.ts @@ -1,4 +1,4 @@ -/* tslint:disable */ +/* eslint-disable */ // This file was automatically generated and should not be edited. // A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies. diff --git a/packages/quicktype-graphql-input/src/index.ts b/packages/quicktype-graphql-input/src/index.ts index bd3cc0feb..515c5c258 100644 --- a/packages/quicktype-graphql-input/src/index.ts +++ b/packages/quicktype-graphql-input/src/index.ts @@ -1,5 +1,3 @@ -/* tslint:disable:strict-boolean-expressions */ - import { DocumentNode, SelectionSetNode, diff --git a/packages/quicktype-typescript-input/package.json b/packages/quicktype-typescript-input/package.json index 9926b394e..813c0575e 100644 --- a/packages/quicktype-typescript-input/package.json +++ b/packages/quicktype-typescript-input/package.json @@ -8,8 +8,7 @@ "repository": "https://github.com/quicktype/quicktype", "scripts": { "clean": "rm -rf dist node_modules *~", - "build": "tsc", - "tslint": "tslint --project ." + "build": "tsc" }, "dependencies": { "quicktype-core": "file:../quicktype-core", @@ -17,8 +16,7 @@ "@mark.probst/typescript-json-schema": "0.55.0" }, "devDependencies": { - "@types/node": "18.14.0", - "tslint": "^6.1.3" + "@types/node": "18.14.0" }, "files": [ "dist" diff --git a/src/index.ts b/src/index.ts index 943abdfb9..109161c79 100644 --- a/src/index.ts +++ b/src/index.ts @@ -271,7 +271,6 @@ function inferCLIOptions(opts: Partial, targetLanguage: TargetLangua language = maybeLanguage; } - /* tslint:disable:strict-boolean-expressions */ const options: CLIOptions = { src: opts.src || [], srcUrls: opts.srcUrls, @@ -295,7 +294,6 @@ function inferCLIOptions(opts: Partial, targetLanguage: TargetLangua debug: opts.debug, telemetry: opts.telemetry }; - /* tslint:enable */ for (const flagName of inferenceFlagNames) { const cliName = negatedInferenceFlagName(flagName); options[cliName] = !!opts[cliName]; diff --git a/tslint.json b/tslint.json deleted file mode 100644 index ac74002e7..000000000 --- a/tslint.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "rules": { - "await-promise": true, - "promise-function-async": true, - "no-floating-promises": true, - "align": [true, "parameters", "statements"], - "ban": false, - "class-name": true, - "comment-format": [true, "check-space"], - "curly": false, - "eofline": false, - "forin": true, - "indent": [true, "spaces", 4], - "interface-name": [true, "never-prefix"], - "jsdoc-format": true, - "jsx-no-lambda": false, - "jsx-no-multiline-js": false, - "label-position": true, - "max-line-length": false, - "member-ordering": [true, "static-before-instance"], - - "no-any": false, - - "no-arg": true, - "no-bitwise": false, - "no-console": [false, "log", "error", "debug", "info", "time", "timeEnd", "trace"], - "no-consecutive-blank-lines": true, - "no-construct": true, - "no-debugger": true, - "no-duplicate-variable": true, - "no-empty": [true, "allow-empty-catch"], - "no-eval": true, - "no-shadowed-variable": true, - "no-string-literal": false, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": false, - "no-unsafe-any": false, - "no-unused-expression": true, - "no-use-before-declare": false, - "no-unused-variable": true, - "no-var-keyword": true, - "no-void-expression": false, - "strict-boolean-expressions": true, - "one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"], - "quotemark": [true, "double", "avoid-escape"], - "radix": true, - "semicolon": [true, "always", "ignore-bound-class-methods"], - "switch-default": true, - - "trailing-comma": false, - - "triple-equals": [true, "allow-null-check"], - "typedef": [true, "parameter", "property-declaration"], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [false] - } -} From 92bd5635a79b141b50ca051290793184ae9696be Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 7 Apr 2024 08:59:27 -0700 Subject: [PATCH 06/80] eslint autofix --- packages/quicktype-core/src/Annotation.ts | 6 +- .../quicktype-core/src/ConvenienceRenderer.ts | 326 ++++--- packages/quicktype-core/src/CycleBreaker.ts | 14 +- packages/quicktype-core/src/DateTime.ts | 16 +- packages/quicktype-core/src/DeclarationIR.ts | 34 +- packages/quicktype-core/src/GatherNames.ts | 42 +- packages/quicktype-core/src/Graph.ts | 39 +- packages/quicktype-core/src/GraphRewriting.ts | 196 ++-- .../quicktype-core/src/MakeTransformations.ts | 130 +-- packages/quicktype-core/src/MarkovChain.ts | 54 +- packages/quicktype-core/src/Messages.ts | 139 +-- packages/quicktype-core/src/Naming.ts | 100 +- packages/quicktype-core/src/Renderer.ts | 137 +-- .../quicktype-core/src/RendererOptions.ts | 61 +- packages/quicktype-core/src/Run.ts | 270 +++--- packages/quicktype-core/src/Source.ts | 86 +- packages/quicktype-core/src/TargetLanguage.ts | 55 +- packages/quicktype-core/src/Transformers.ts | 361 ++++---- packages/quicktype-core/src/Type.ts | 283 +++--- packages/quicktype-core/src/TypeBuilder.ts | 198 ++-- packages/quicktype-core/src/TypeGraph.ts | 171 ++-- packages/quicktype-core/src/TypeUtils.ts | 125 +-- packages/quicktype-core/src/UnifyClasses.ts | 69 +- packages/quicktype-core/src/UnionBuilder.ts | 123 +-- .../src/attributes/AccessorNames.ts | 59 +- .../src/attributes/Constraints.ts | 70 +- .../src/attributes/Description.ts | 45 +- .../src/attributes/EnumValues.ts | 20 +- .../src/attributes/StringTypes.ts | 72 +- .../src/attributes/TypeAttributes.ts | 61 +- .../src/attributes/TypeNames.ts | 103 ++- .../src/attributes/URIAttributes.ts | 30 +- packages/quicktype-core/src/index.ts | 56 +- .../src/input/CompressedJSON.ts | 96 +- .../src/input/FetchingJSONSchemaStore.ts | 7 +- .../quicktype-core/src/input/Inference.ts | 86 +- packages/quicktype-core/src/input/Inputs.ts | 94 +- .../src/input/JSONSchemaInput.ts | 349 ++++--- .../src/input/JSONSchemaStore.ts | 15 +- .../src/input/PostmanCollection.ts | 17 +- .../quicktype-core/src/input/io/NodeIO.ts | 12 +- .../src/input/io/get-stream/buffer-stream.ts | 6 +- .../src/input/io/get-stream/index.ts | 14 +- packages/quicktype-core/src/language/All.ts | 9 +- packages/quicktype-core/src/language/CJSON.ts | 851 +++++++++--------- .../quicktype-core/src/language/CPlusPlus.ts | 830 +++++++++-------- .../quicktype-core/src/language/CSharp.ts | 576 +++++++----- .../quicktype-core/src/language/Crystal.ts | 93 +- packages/quicktype-core/src/language/Dart.ts | 261 +++--- packages/quicktype-core/src/language/Elm.ts | 186 ++-- .../quicktype-core/src/language/Golang.ts | 142 +-- .../quicktype-core/src/language/Haskell.ts | 141 +-- .../quicktype-core/src/language/JSONSchema.ts | 79 +- packages/quicktype-core/src/language/Java.ts | 435 +++++---- .../quicktype-core/src/language/JavaScript.ts | 179 ++-- .../src/language/JavaScriptPropTypes.ts | 90 +- .../src/language/JavaScriptUnicodeMaps.ts | 24 +- .../quicktype-core/src/language/Kotlin.ts | 300 +++--- .../src/language/Objective-C.ts | 274 +++--- packages/quicktype-core/src/language/Php.ts | 329 ++++--- packages/quicktype-core/src/language/Pike.ts | 95 +- .../quicktype-core/src/language/Python.ts | 417 +++++---- packages/quicktype-core/src/language/Rust.ts | 154 ++-- .../quicktype-core/src/language/Scala3.ts | 204 +++-- .../quicktype-core/src/language/Smithy4s.ts | 164 ++-- packages/quicktype-core/src/language/Swift.ts | 283 +++--- .../src/language/TypeScriptEffectSchema.ts | 80 +- .../src/language/TypeScriptFlow.ts | 137 +-- .../src/language/TypeScriptZod.ts | 131 +-- .../quicktype-core/src/language/ruby/index.ts | 167 ++-- .../src/language/ruby/keywords.ts | 8 +- .../src/rewrites/CombineClasses.ts | 45 +- .../src/rewrites/ExpandStrings.ts | 41 +- .../src/rewrites/FlattenStrings.ts | 26 +- .../src/rewrites/FlattenUnions.ts | 17 +- .../quicktype-core/src/rewrites/InferMaps.ts | 34 +- .../src/rewrites/ReplaceObjectType.ts | 24 +- .../src/rewrites/ResolveIntersections.ts | 108 ++- .../quicktype-core/src/support/Acronyms.ts | 16 +- packages/quicktype-core/src/support/Chance.ts | 84 +- .../quicktype-core/src/support/Comments.ts | 22 +- .../quicktype-core/src/support/Converters.ts | 10 +- .../quicktype-core/src/support/Strings.ts | 170 ++-- .../quicktype-core/src/support/Support.ts | 59 +- packages/quicktype-graphql-input/src/index.ts | 199 ++-- .../quicktype-typescript-input/src/index.ts | 19 +- src/CompressedJSONFromStream.ts | 21 +- src/GraphQLIntrospection.ts | 14 +- src/TypeSource.ts | 6 +- src/URLGrammar.ts | 12 +- src/index.ts | 286 +++--- 91 files changed, 6685 insertions(+), 5414 deletions(-) diff --git a/packages/quicktype-core/src/Annotation.ts b/packages/quicktype-core/src/Annotation.ts index 8a912f305..e6483462c 100644 --- a/packages/quicktype-core/src/Annotation.ts +++ b/packages/quicktype-core/src/Annotation.ts @@ -1,14 +1,14 @@ export class AnnotationData {} export class IssueAnnotationData extends AnnotationData { - constructor(readonly message: string) { + constructor (readonly message: string) { super(); } } export const anyTypeIssueAnnotation = new IssueAnnotationData( - "quicktype cannot infer this type because there is no data about it in the input." + "quicktype cannot infer this type because there is no data about it in the input.", ); export const nullTypeIssueAnnotation = new IssueAnnotationData( - "The only value for this in the input is null, which means you probably need a more complete input sample." + "The only value for this in the input is null, which means you probably need a more complete input sample.", ); diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index ec80df6f5..175db7e3e 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -6,24 +6,30 @@ import { mapFilter, mapSortBy, mapFilterMap, - mapSome + mapSome, } from "collection-utils"; -import { Type, ClassType, EnumType, UnionType, TypeKind, ClassProperty, MapType, ObjectType } from "./Type"; +import { type Type, type TypeKind, type ClassProperty} from "./Type"; +import { ClassType, EnumType, UnionType, MapType, ObjectType } from "./Type"; import { separateNamedTypes, nullableFromUnion, matchTypeExhaustive, isNamedType } from "./TypeUtils"; -import { Namespace, Name, Namer, FixedName, SimpleName, DependencyName, keywordNamespace } from "./Naming"; -import { Renderer, BlankLineConfig, RenderContext, ForEachPosition } from "./Renderer"; +import { type Name, type Namer} from "./Naming"; +import { Namespace, FixedName, SimpleName, DependencyName, keywordNamespace } from "./Naming"; +import { type BlankLineConfig, type RenderContext, type ForEachPosition } from "./Renderer"; +import { Renderer } from "./Renderer"; import { defined, panic, nonNull, assert } from "./support/Support"; import { trimEnd } from "./support/Strings"; -import { Sourcelike, sourcelikeToSource, serializeRenderResult } from "./Source"; +import { type Sourcelike} from "./Source"; +import { sourcelikeToSource, serializeRenderResult } from "./Source"; -import { declarationsForGraph, DeclarationIR, cycleBreakerTypesForGraph, Declaration } from "./DeclarationIR"; +import { type DeclarationIR, type Declaration } from "./DeclarationIR"; +import { declarationsForGraph, cycleBreakerTypesForGraph } from "./DeclarationIR"; import { TypeAttributeStoreView } from "./TypeGraph"; import { TypeAttributeKind } from "./attributes/TypeAttributes"; import { descriptionTypeAttributeKind, propertyDescriptionsTypeAttributeKind } from "./attributes/Description"; import { enumCaseNames, objectPropertyNames, unionMemberName, getAccessorName } from "./attributes/AccessorNames"; -import { transformationForType, followTargetType, Transformation } from "./Transformers"; -import { TargetLanguage } from "./TargetLanguage"; +import { type Transformation } from "./Transformers"; +import { transformationForType, followTargetType } from "./Transformers"; +import { type TargetLanguage } from "./TargetLanguage"; import { type Comment, isStringComment, type CommentOptions } from "./support/Comments"; const wordWrap: (s: string) => string = require("wordwrap")(90); @@ -41,7 +47,7 @@ const assignedEnumCaseNameOrder = 10; const unionMemberNameOrder = 40; -function splitDescription(descriptions: Iterable | undefined): string[] | undefined { +function splitDescription (descriptions: Iterable | undefined): string[] | undefined { if (descriptions === undefined) return undefined; const description = Array.from(descriptions).join("\n\n").trim(); if (description === "") return undefined; @@ -50,7 +56,9 @@ function splitDescription(descriptions: Iterable | undefined): string[] .map(l => l.trim()); } -export type ForbiddenWordsInfo = { names: (Name | string)[]; includeGlobalForbidden: boolean }; +export interface ForbiddenWordsInfo { + includeGlobalForbidden: boolean; names: Array; +} const assignedNameAttributeKind = new TypeAttributeKind("assignedName"); const assignedPropertyNamesAttributeKind = new TypeAttributeKind>("assignedPropertyNames"); @@ -59,37 +67,54 @@ const assignedCaseNamesAttributeKind = new TypeAttributeKind | undefined; + private _globalNamespace: Namespace | undefined; + private _nameStoreView: TypeAttributeStoreView | undefined; + private _propertyNamesStoreView: TypeAttributeStoreView> | undefined; + private _memberNamesStoreView: TypeAttributeStoreView> | undefined; + private _caseNamesStoreView: TypeAttributeStoreView> | undefined; + private _namesForTransformations: Map | undefined; private _namedTypeNamer: Namer | undefined; - // @ts-ignore: FIXME: Make this `Namer | undefined` + + // @ts-expect-error: FIXME: Make this `Namer | undefined` private _unionMemberNamer: Namer | null; - // @ts-ignore: FIXME: Make this `Namer | undefined` + + // @ts-expect-error: FIXME: Make this `Namer | undefined` private _enumCaseNamer: Namer | null; private _declarationIR: DeclarationIR | undefined; - private _namedTypes: ReadonlyArray | undefined; + + private _namedTypes: readonly Type[] | undefined; + private _namedObjects: Set | undefined; + private _namedEnums: Set | undefined; + private _namedUnions: Set | undefined; + private _haveUnions: boolean | undefined; + private _haveMaps: boolean | undefined; + private _haveOptionalProperties: boolean | undefined; + private _cycleBreakerTypes?: Set | undefined; private _alphabetizeProperties = false; - constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) { + constructor (targetLanguage: TargetLanguage, renderContext: RenderContext) { super(targetLanguage, renderContext); } - get topLevels(): ReadonlyMap { + get topLevels (): ReadonlyMap { return this.typeGraph.topLevels; } @@ -100,7 +125,7 @@ export abstract class ConvenienceRenderer extends Renderer { * that can conflict with that, such as reserved keywords or common type * names. */ - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return []; } @@ -114,95 +139,96 @@ export abstract class ConvenienceRenderer extends Renderer { * Note: That doesn't mean that the names in the global namespace will be * forbidden, too! */ - protected forbiddenForObjectProperties(_o: ObjectType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_o: ObjectType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected makeTopLevelDependencyNames(_t: Type, _topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames (_t: Type, _topLevelName: Name): DependencyName[] { return []; } - protected makeNamedTypeDependencyNames(_t: Type, _name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames (_t: Type, _name: Name): DependencyName[] { return []; } - protected abstract makeNamedTypeNamer(): Namer; - protected abstract namerForObjectProperty(o: ObjectType, p: ClassProperty): Namer | null; - protected abstract makeUnionMemberNamer(): Namer | null; - protected abstract makeEnumCaseNamer(): Namer | null; - protected abstract emitSourceStructure(givenOutputFilename: string): void; + protected abstract makeNamedTypeNamer (): Namer; + protected abstract namerForObjectProperty (o: ObjectType, p: ClassProperty): Namer | null; + protected abstract makeUnionMemberNamer (): Namer | null; + protected abstract makeEnumCaseNamer (): Namer | null; + protected abstract emitSourceStructure (givenOutputFilename: string): void; - protected makeNameForTransformation(_xf: Transformation, _typeName: Name | undefined): Name | undefined { + protected makeNameForTransformation (_xf: Transformation, _typeName: Name | undefined): Name | undefined { return undefined; } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { if (isNamedType(type)) { return type; } + return undefined; } - protected get unionMembersInGlobalNamespace(): boolean { + protected get unionMembersInGlobalNamespace (): boolean { return false; } - protected get enumCasesInGlobalNamespace(): boolean { + protected get enumCasesInGlobalNamespace (): boolean { return false; } - protected get needsTypeDeclarationBeforeUse(): boolean { + protected get needsTypeDeclarationBeforeUse (): boolean { return false; } - protected canBeForwardDeclared(_t: Type): boolean { + protected canBeForwardDeclared (_t: Type): boolean { return panic("If needsTypeDeclarationBeforeUse returns true, canBeForwardDeclared must be implemented"); } - protected unionNeedsName(u: UnionType): boolean { + protected unionNeedsName (u: UnionType): boolean { return nullableFromUnion(u) === null; } - private get globalNamespace(): Namespace { + private get globalNamespace (): Namespace { return defined(this._globalNamespace); } - private get nameStoreView(): TypeAttributeStoreView { + private get nameStoreView (): TypeAttributeStoreView { return defined(this._nameStoreView); } - protected descriptionForType(t: Type): string[] | undefined { + protected descriptionForType (t: Type): string[] | undefined { let description = this.typeGraph.attributeStore.tryGet(descriptionTypeAttributeKind, t); return splitDescription(description); } - protected descriptionForClassProperty(o: ObjectType, name: string): string[] | undefined { + protected descriptionForClassProperty (o: ObjectType, name: string): string[] | undefined { const descriptions = this.typeGraph.attributeStore.tryGet(propertyDescriptionsTypeAttributeKind, o); if (descriptions === undefined) return undefined; return splitDescription(descriptions.get(name)); } - protected setUpNaming(): ReadonlySet { + protected setUpNaming (): ReadonlySet { this._nameStoreView = new TypeAttributeStoreView(this.typeGraph.attributeStore, assignedNameAttributeKind); this._propertyNamesStoreView = new TypeAttributeStoreView( this.typeGraph.attributeStore, - assignedPropertyNamesAttributeKind + assignedPropertyNamesAttributeKind, ); this._memberNamesStoreView = new TypeAttributeStoreView( this.typeGraph.attributeStore, - assignedMemberNamesAttributeKind + assignedMemberNamesAttributeKind, ); this._caseNamesStoreView = new TypeAttributeStoreView( this.typeGraph.attributeStore, - assignedCaseNamesAttributeKind + assignedCaseNamesAttributeKind, ); this._namesForTransformations = new Map(); @@ -218,40 +244,44 @@ export abstract class ConvenienceRenderer extends Renderer { for (const [name, t] of this.topLevels) { this.nameStoreView.setForTopLevel(name, this.addNameForTopLevel(t, name)); } + for (const o of objects) { const name = this.addNameForNamedType(o); this.addPropertyNames(o, name); } + for (const e of enums) { const name = this.addNameForNamedType(e); this.addEnumCaseNames(e, name); } + for (const u of namedUnions) { const name = this.addNameForNamedType(u); this.addUnionMemberNames(u, name); } + for (const t of this.typeGraph.allTypesUnordered()) { this.addNameForTransformation(t); } return setUnion( [this._globalForbiddenNamespace, this._globalNamespace], - this._otherForbiddenNamespaces.values() + this._otherForbiddenNamespaces.values(), ); } - private addDependenciesForNamedType(type: Type, named: Name): void { + private addDependenciesForNamedType (type: Type, named: Name): void { const dependencyNames = this.makeNamedTypeDependencyNames(type, named); for (const dn of dependencyNames) { this.globalNamespace.add(dn); } } - protected makeNameForTopLevel(_t: Type, givenName: string, _maybeNamedType: Type | undefined): Name { + protected makeNameForTopLevel (_t: Type, givenName: string, _maybeNamedType: Type | undefined): Name { return new SimpleName([givenName], defined(this._namedTypeNamer), topLevelNameOrder); } - private addNameForTopLevel(type: Type, givenName: string): Name { + private addNameForTopLevel (type: Type, givenName: string): Name { const maybeNamedType = this.namedTypeToNameForTopLevel(type); const name = this.makeNameForTopLevel(type, givenName, maybeNamedType); this.globalNamespace.add(name); @@ -268,17 +298,17 @@ export abstract class ConvenienceRenderer extends Renderer { return name; } - private makeNameForType(t: Type, namer: Namer, givenOrder: number, inferredOrder: number): Name { + private makeNameForType (t: Type, namer: Namer, givenOrder: number, inferredOrder: number): Name { const names = t.getNames(); const order = names.areInferred ? inferredOrder : givenOrder; return new SimpleName(names.proposedNames, namer, order); } - protected makeNameForNamedType(t: Type): Name { + protected makeNameForNamedType (t: Type): Name { return this.makeNameForType(t, defined(this._namedTypeNamer), givenNameOrder, inferredNameOrder); } - private addNameForNamedType(type: Type): Name { + private addNameForNamedType (type: Type): Name { const existing = this.nameStoreView.tryGet(type); if (existing !== undefined) return existing; @@ -290,11 +320,11 @@ export abstract class ConvenienceRenderer extends Renderer { return name; } - protected get typesWithNamedTransformations(): ReadonlyMap { + protected get typesWithNamedTransformations (): ReadonlyMap { return defined(this._namesForTransformations); } - protected nameForTransformation(t: Type): Name | undefined { + protected nameForTransformation (t: Type): Name | undefined { const xf = transformationForType(t); if (xf === undefined) return undefined; @@ -302,16 +332,17 @@ export abstract class ConvenienceRenderer extends Renderer { if (name === undefined) { return panic("No name for transformation"); } + return name; } - private addNameForTransformation(t: Type): void { + private addNameForTransformation (t: Type): void { const xf = transformationForType(t); if (xf === undefined) return; assert( defined(this._namesForTransformations).get(t) === undefined, - "Tried to give two names to the same transformation" + "Tried to give two names to the same transformation", ); const name = this.makeNameForTransformation(xf, this.nameStoreView.tryGet(xf.targetType)); @@ -321,10 +352,10 @@ export abstract class ConvenienceRenderer extends Renderer { defined(this._namesForTransformations).set(t, name); } - private processForbiddenWordsInfo( + private processForbiddenWordsInfo ( info: ForbiddenWordsInfo, - namespaceName: string - ): { forbiddenNames: ReadonlySet; forbiddenNamespaces: ReadonlySet } { + namespaceName: string, + ): { forbiddenNames: ReadonlySet, forbiddenNamespaces: ReadonlySet, } { const forbiddenNames: Name[] = []; const forbiddenStrings: string[] = []; for (const nameOrString of info.names) { @@ -334,15 +365,18 @@ export abstract class ConvenienceRenderer extends Renderer { forbiddenNames.push(nameOrString); } } + let namespace = defined(this._otherForbiddenNamespaces).get(namespaceName); if (forbiddenStrings.length > 0 && namespace === undefined) { namespace = keywordNamespace(namespaceName, forbiddenStrings); this._otherForbiddenNamespaces = defined(this._otherForbiddenNamespaces).set(namespaceName, namespace); } + let forbiddenNamespaces = new Set(); if (info.includeGlobalForbidden) { forbiddenNamespaces = forbiddenNamespaces.add(defined(this._globalForbiddenNamespace)); } + if (namespace !== undefined) { forbiddenNamespaces = forbiddenNamespaces.add(namespace); } @@ -350,12 +384,12 @@ export abstract class ConvenienceRenderer extends Renderer { return { forbiddenNames: new Set(forbiddenNames), forbiddenNamespaces }; } - protected makeNameForProperty( + protected makeNameForProperty ( o: ObjectType, _className: Name, p: ClassProperty, jsonName: string, - assignedName: string | undefined + assignedName: string | undefined, ): Name | undefined { const namer = this.namerForObjectProperty(o, p); if (namer === null) return undefined; @@ -374,20 +408,20 @@ export abstract class ConvenienceRenderer extends Renderer { return new SimpleName(names, namer, order); } - protected makePropertyDependencyNames( + protected makePropertyDependencyNames ( _o: ObjectType, _className: Name, _p: ClassProperty, _jsonName: string, - _name: Name + _name: Name, ): Name[] { return []; } - private addPropertyNames(o: ObjectType, className: Name): void { + private addPropertyNames (o: ObjectType, className: Name): void { const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( this.forbiddenForObjectProperties(o, className), - "forbidden-for-properties" + "forbidden-for-properties", ); let ns: Namespace | undefined; @@ -401,37 +435,41 @@ export abstract class ConvenienceRenderer extends Renderer { } else { name = this.makeNameForProperty(o, className, p, jsonName, assignedName); } + if (name === undefined) return undefined; if (ns === undefined) { ns = new Namespace(o.getCombinedName(), this.globalNamespace, forbiddenNamespaces, forbiddenNames); } + ns.add(name); for (const depName of this.makePropertyDependencyNames(o, className, p, jsonName, name)) { ns.add(depName); } + return name; }); defined(this._propertyNamesStoreView).set(o, names); } - protected makeNameForUnionMember(u: UnionType, unionName: Name, t: Type): Name { + protected makeNameForUnionMember (u: UnionType, unionName: Name, t: Type): Name { const [assignedName, isFixed] = unionMemberName(u, t, this.targetLanguage.name); if (isFixed) { return new FixedName(defined(assignedName)); } + return new DependencyName(nonNull(this._unionMemberNamer), unionMemberNameOrder, lookup => { if (assignedName !== undefined) return assignedName; return this.proposeUnionMemberName(u, unionName, t, lookup); }); } - private addUnionMemberNames(u: UnionType, unionName: Name): void { + private addUnionMemberNames (u: UnionType, unionName: Name): void { const memberNamer = this._unionMemberNamer; if (memberNamer === null) return; const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( this.forbiddenForUnionMembers(u, unionName), - "forbidden-for-union-members" + "forbidden-for-union-members", ); let ns: Namespace; @@ -440,19 +478,21 @@ export abstract class ConvenienceRenderer extends Renderer { } else { ns = new Namespace(u.getCombinedName(), this.globalNamespace, forbiddenNamespaces, forbiddenNames); } + let names = new Map(); for (const t of u.members) { const name = this.makeNameForUnionMember(u, unionName, followTargetType(t)); names.set(t, ns.add(name)); } + defined(this._memberNamesStoreView).set(u, names); } - protected makeNameForEnumCase( + protected makeNameForEnumCase ( e: EnumType, _enumName: Name, caseName: string, - assignedName: string | undefined + assignedName: string | undefined, ): Name { // FIXME: See the FIXME in `makeNameForProperty`. We do have global // enum cases, though (in Go), so this is actually useful already. @@ -463,12 +503,12 @@ export abstract class ConvenienceRenderer extends Renderer { } // FIXME: this is very similar to addPropertyNameds and addUnionMemberNames - private addEnumCaseNames(e: EnumType, enumName: Name): void { + private addEnumCaseNames (e: EnumType, enumName: Name): void { if (this._enumCaseNamer === null) return; const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( this.forbiddenForEnumCases(e, enumName), - "forbidden-for-enum-cases" + "forbidden-for-enum-cases", ); let ns: Namespace; @@ -477,6 +517,7 @@ export abstract class ConvenienceRenderer extends Renderer { } else { ns = new Namespace(e.getCombinedName(), this.globalNamespace, forbiddenNamespaces, forbiddenNames); } + let names = new Map(); const accessorNames = enumCaseNames(e, this.targetLanguage.name); for (const caseName of e.cases) { @@ -487,12 +528,14 @@ export abstract class ConvenienceRenderer extends Renderer { } else { name = this.makeNameForEnumCase(e, enumName, caseName, assignedName); } + names.set(caseName, ns.add(name)); } + defined(this._caseNamesStoreView).set(e, names); } - private childrenOfType(t: Type): ReadonlySet { + private childrenOfType (t: Type): ReadonlySet { const names = this.names; if (t instanceof ClassType) { const propertyNameds = defined(this._propertyNamesStoreView).get(t); @@ -503,52 +546,53 @@ export abstract class ConvenienceRenderer extends Renderer { const sortedMap = mapSortBy(filteredMap, (_, n) => defined(names.get(defined(propertyNameds.get(n))))); return new Set(sortedMap.values()); } + return t.getChildren(); } - protected get namedUnions(): ReadonlySet { + protected get namedUnions (): ReadonlySet { return defined(this._namedUnions); } - protected get haveNamedUnions(): boolean { + protected get haveNamedUnions (): boolean { return this.namedUnions.size > 0; } - protected get haveNamedTypes(): boolean { + protected get haveNamedTypes (): boolean { return defined(this._namedTypes).length > 0; } - protected get haveUnions(): boolean { + protected get haveUnions (): boolean { return defined(this._haveUnions); } - protected get haveMaps(): boolean { + protected get haveMaps (): boolean { return defined(this._haveMaps); } - protected get haveOptionalProperties(): boolean { + protected get haveOptionalProperties (): boolean { return defined(this._haveOptionalProperties); } // FIXME: Inconsistently named, though technically correct. Right now all enums are named, // but this should really be called `namedEnums`. - protected get enums(): ReadonlySet { + protected get enums (): ReadonlySet { return defined(this._namedEnums); } - protected get haveEnums(): boolean { + protected get haveEnums (): boolean { return this.enums.size > 0; } - protected proposedUnionMemberNameForTypeKind(_kind: TypeKind): string | null { + protected proposedUnionMemberNameForTypeKind (_kind: TypeKind): string | null { return null; } - protected proposeUnionMemberName( + protected proposeUnionMemberName ( _u: UnionType, _unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { const simpleName = this.proposedUnionMemberNameForTypeKind(fieldType.kind); if (simpleName !== null) { @@ -573,49 +617,50 @@ export abstract class ConvenienceRenderer extends Renderer { objectType => { assert( this.targetLanguage.supportsFullObjectType, - "Object type should have been replaced in `replaceObjectType`" + "Object type should have been replaced in `replaceObjectType`", ); return lookup(this.nameForNamedType(objectType)); }, _enumType => "enum", _unionType => "union", - transformedType => transformedType.kind.replace("-", "_") + transformedType => transformedType.kind.replace("-", "_"), ); return typeNameForUnionMember(fieldType); } - protected nameForNamedType(t: Type): Name { + protected nameForNamedType (t: Type): Name { return this.nameStoreView.get(t); } - protected isForwardDeclaredType(t: Type): boolean { + protected isForwardDeclaredType (t: Type): boolean { return defined(this._declarationIR).forwardedTypes.has(t); } - protected isImplicitCycleBreaker(_t: Type): boolean { + protected isImplicitCycleBreaker (_t: Type): boolean { return panic("A renderer that invokes isCycleBreakerType must implement isImplicitCycleBreaker"); } - protected canBreakCycles(_t: Type): boolean { + protected canBreakCycles (_t: Type): boolean { return true; } - protected isCycleBreakerType(t: Type): boolean { + protected isCycleBreakerType (t: Type): boolean { if (this._cycleBreakerTypes === undefined) { this._cycleBreakerTypes = cycleBreakerTypesForGraph( this.typeGraph, s => this.isImplicitCycleBreaker(s), - s => this.canBreakCycles(s) + s => this.canBreakCycles(s), ); } + return this._cycleBreakerTypes.has(t); } - protected forEachTopLevel( + protected forEachTopLevel ( blankLocations: BlankLineConfig, f: (t: Type, name: Name, position: ForEachPosition) => void, - predicate?: (t: Type) => boolean + predicate?: (t: Type) => boolean, ): boolean { let topLevels: ReadonlyMap; if (predicate !== undefined) { @@ -623,39 +668,40 @@ export abstract class ConvenienceRenderer extends Renderer { } else { topLevels = this.topLevels; } + return this.forEachWithBlankLines(topLevels, blankLocations, (t, name, pos) => - f(t, this.nameStoreView.getForTopLevel(name), pos) + f(t, this.nameStoreView.getForTopLevel(name), pos), ); } - protected forEachDeclaration( + protected forEachDeclaration ( blankLocations: BlankLineConfig, - f: (decl: Declaration, position: ForEachPosition) => void + f: (decl: Declaration, position: ForEachPosition) => void, ) { this.forEachWithBlankLines( iterableEnumerate(defined(this._declarationIR).declarations), blankLocations, - (decl, _, pos) => f(decl, pos) + (decl, _, pos) => f(decl, pos), ); } - setAlphabetizeProperties(value: boolean): void { + setAlphabetizeProperties (value: boolean): void { this._alphabetizeProperties = value; } - protected getAlphabetizeProperties(): boolean { + protected getAlphabetizeProperties (): boolean { return this._alphabetizeProperties; } // Returns the number of properties defined for the specified object type. - protected propertyCount(o: ObjectType): number { + protected propertyCount (o: ObjectType): number { const propertyNames = defined(this._propertyNamesStoreView).get(o); return propertyNames.size; } - protected sortClassProperties( + protected sortClassProperties ( properties: ReadonlyMap, - propertyNames: ReadonlyMap + propertyNames: ReadonlyMap, ): ReadonlyMap { if (this._alphabetizeProperties) { return mapSortBy(properties, (_p: ClassProperty, jsonName: string) => { @@ -667,10 +713,10 @@ export abstract class ConvenienceRenderer extends Renderer { } } - protected forEachClassProperty( + protected forEachClassProperty ( o: ObjectType, blankLocations: BlankLineConfig, - f: (name: Name, jsonName: string, p: ClassProperty, position: ForEachPosition) => void + f: (name: Name, jsonName: string, p: ClassProperty, position: ForEachPosition) => void, ): void { const propertyNames = defined(this._propertyNamesStoreView).get(o); const sortedProperties = this.sortClassProperties(o.getProperties(), propertyNames); @@ -680,44 +726,45 @@ export abstract class ConvenienceRenderer extends Renderer { }); } - protected nameForUnionMember(u: UnionType, t: Type): Name { + protected nameForUnionMember (u: UnionType, t: Type): Name { return defined(defined(this._memberNamesStoreView).get(u).get(t)); } - protected nameForEnumCase(e: EnumType, caseName: string): Name { + protected nameForEnumCase (e: EnumType, caseName: string): Name { const caseNames = defined(this._caseNamesStoreView).get(e); return defined(caseNames.get(caseName)); } - protected forEachUnionMember( + protected forEachUnionMember ( u: UnionType, members: ReadonlySet | null, blankLocations: BlankLineConfig, sortOrder: ((n: Name, t: Type) => string) | null, - f: (name: Name, t: Type, position: ForEachPosition) => void + f: (name: Name, t: Type, position: ForEachPosition) => void, ): void { const iterateMembers = members === null ? u.members : members; if (sortOrder === null) { sortOrder = n => defined(this.names.get(n)); } + const memberNames = mapFilter(defined(this._memberNamesStoreView).get(u), (_, t) => iterateMembers.has(t)); const sortedMemberNames = mapSortBy(memberNames, sortOrder); this.forEachWithBlankLines(sortedMemberNames, blankLocations, f); } - protected forEachEnumCase( + protected forEachEnumCase ( e: EnumType, blankLocations: BlankLineConfig, - f: (name: Name, jsonName: string, position: ForEachPosition) => void + f: (name: Name, jsonName: string, position: ForEachPosition) => void, ): void { const caseNames = defined(this._caseNamesStoreView).get(e); const sortedCaseNames = mapSortBy(caseNames, n => defined(this.names.get(n))); this.forEachWithBlankLines(sortedCaseNames, blankLocations, f); } - protected forEachTransformation( + protected forEachTransformation ( blankLocations: BlankLineConfig, - f: (n: Name, t: Type, position: ForEachPosition) => void + f: (n: Name, t: Type, position: ForEachPosition) => void, ): void { this.forEachWithBlankLines(defined(this._namesForTransformations), blankLocations, f); } @@ -725,31 +772,31 @@ export abstract class ConvenienceRenderer extends Renderer { protected forEachSpecificNamedType( blankLocations: BlankLineConfig, types: Iterable<[any, T]>, - f: (t: T, name: Name, position: ForEachPosition) => void + f: (t: T, name: Name, position: ForEachPosition) => void, ): void { this.forEachWithBlankLines(types, blankLocations, (t, _, pos) => f(t, this.nameForNamedType(t), pos)); } - protected forEachObject( + protected forEachObject ( blankLocations: BlankLineConfig, f: - | ((c: ClassType, className: Name, position: ForEachPosition) => void) - | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void) + | ((c: ClassType, className: Name, position: ForEachPosition) => void) + | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void), ): void { // FIXME: This is ugly. this.forEachSpecificNamedType(blankLocations, defined(this._namedObjects).entries(), f as any); } - protected forEachEnum( + protected forEachEnum ( blankLocations: BlankLineConfig, - f: (u: EnumType, enumName: Name, position: ForEachPosition) => void + f: (u: EnumType, enumName: Name, position: ForEachPosition) => void, ): void { this.forEachSpecificNamedType(blankLocations, this.enums.entries(), f); } - protected forEachUnion( + protected forEachUnion ( blankLocations: BlankLineConfig, - f: (u: UnionType, unionName: Name, position: ForEachPosition) => void + f: (u: UnionType, unionName: Name, position: ForEachPosition) => void, ): void { this.forEachSpecificNamedType(blankLocations, this.namedUnions.entries(), f); } @@ -757,7 +804,7 @@ export abstract class ConvenienceRenderer extends Renderer { protected forEachUniqueUnion( blankLocations: BlankLineConfig, uniqueValue: (u: UnionType) => T, - f: (firstUnion: UnionType, value: T, position: ForEachPosition) => void + f: (firstUnion: UnionType, value: T, position: ForEachPosition) => void, ): void { const firstUnionByValue = new Map(); for (const u of this.namedUnions) { @@ -766,16 +813,17 @@ export abstract class ConvenienceRenderer extends Renderer { firstUnionByValue.set(v, u); } } + this.forEachWithBlankLines(firstUnionByValue, blankLocations, f); } - protected forEachNamedType( + protected forEachNamedType ( blankLocations: BlankLineConfig, objectFunc: - | ((c: ClassType, className: Name, position: ForEachPosition) => void) - | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void), + | ((c: ClassType, className: Name, position: ForEachPosition) => void) + | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void), enumFunc: (e: EnumType, enumName: Name, position: ForEachPosition) => void, - unionFunc: (u: UnionType, unionName: Name, position: ForEachPosition) => void + unionFunc: (u: UnionType, unionName: Name, position: ForEachPosition) => void, ): void { this.forEachWithBlankLines(defined(this._namedTypes).entries(), blankLocations, (t, _, pos) => { const name = this.nameForNamedType(t); @@ -796,15 +844,15 @@ export abstract class ConvenienceRenderer extends Renderer { // You should never have to use this to produce parts of your generated // code. If you need to modify a Name, for example to change its casing, // use `modifySource`. - protected sourcelikeToString(src: Sourcelike): string { + protected sourcelikeToString (src: Sourcelike): string { return serializeRenderResult(sourcelikeToSource(src), this.names, "").lines.join("\n"); } - protected get commentLineStart(): string { + protected get commentLineStart (): string { return "// "; } - protected emitComments(comments: Comment[]): void { + protected emitComments (comments: Comment[]): void { comments.forEach(comment => { if (isStringComment(comment)) { this.emitCommentLines([comment]); @@ -820,19 +868,20 @@ export abstract class ConvenienceRenderer extends Renderer { }); } - protected emitCommentLines( + protected emitCommentLines ( lines: Sourcelike[], { lineStart = this.commentLineStart, firstLineStart = lineStart, lineEnd, beforeComment, - afterComment - }: CommentOptions = {} + afterComment, + }: CommentOptions = {}, ): void { if (beforeComment !== undefined) { this.emitLine(beforeComment); } + let first = true; for (const line of lines) { let start = first ? firstLineStart : lineStart; @@ -848,24 +897,25 @@ export abstract class ConvenienceRenderer extends Renderer { this.emitLine(start, line); } } + if (afterComment !== undefined) { this.emitLine(afterComment); } } - protected emitDescription(description: Sourcelike[] | undefined): void { + protected emitDescription (description: Sourcelike[] | undefined): void { if (description === undefined) return; // FIXME: word-wrap this.emitDescriptionBlock(description); } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines); } - protected emitPropertyTable( + protected emitPropertyTable ( c: ClassType, - makePropertyRow: (name: Name, jsonName: string, p: ClassProperty) => Sourcelike[] + makePropertyRow: (name: Name, jsonName: string, p: ClassProperty) => Sourcelike[], ): void { let table: Sourcelike[][] = []; const emitTable = () => { @@ -880,12 +930,13 @@ export abstract class ConvenienceRenderer extends Renderer { emitTable(); this.emitDescription(description); } + table.push(makePropertyRow(name, jsonName, p)); }); emitTable(); } - private processGraph(): void { + private processGraph (): void { this._declarationIR = declarationsForGraph( this.typeGraph, this.needsTypeDeclarationBeforeUse ? t => this.canBeForwardDeclared(t) : undefined, @@ -894,8 +945,9 @@ export abstract class ConvenienceRenderer extends Renderer { if (t instanceof UnionType) { return this.unionNeedsName(t); } + return isNamedType(t); - } + }, ); const types = this.typeGraph.allTypesUnordered(); @@ -910,7 +962,7 @@ export abstract class ConvenienceRenderer extends Renderer { this._namedUnions = new Set(unions); } - protected emitSource(givenOutputFilename: string): void { + protected emitSource (givenOutputFilename: string): void { this.processGraph(); this.emitSourceStructure(givenOutputFilename); } @@ -920,11 +972,12 @@ export abstract class ConvenienceRenderer extends Renderer { const processed = new Set(); const queue = Array.from(this.typeGraph.topLevels.values()); - function visit(t: Type) { + function visit (t: Type) { if (visitedTypes.has(t)) return; for (const c of t.getChildren()) { queue.push(c); } + visitedTypes.add(t); processed.add(process(t)); } @@ -934,6 +987,7 @@ export abstract class ConvenienceRenderer extends Renderer { if (maybeType === undefined) { break; } + visit(maybeType); } diff --git a/packages/quicktype-core/src/CycleBreaker.ts b/packages/quicktype-core/src/CycleBreaker.ts index d3eba6321..586ae8f49 100644 --- a/packages/quicktype-core/src/CycleBreaker.ts +++ b/packages/quicktype-core/src/CycleBreaker.ts @@ -1,18 +1,19 @@ import { assert, panic } from "./support/Support"; -export function breakCycles(outEdges: number[][], chooseBreaker: (cycle: number[]) => [number, T]): [number, T][] { +export function breakCycles (outEdges: number[][], chooseBreaker: (cycle: number[]) => [number, T]): Array<[number, T]> { const numNodes = outEdges.length; const inEdges: number[][] = []; const inDegree: number[] = []; const outDegree: number[] = []; const done: boolean[] = []; - const results: [number, T][] = []; + const results: Array<[number, T]> = []; for (let i = 0; i < numNodes; i++) { inEdges.push([]); inDegree.push(0); outDegree.push(outEdges[i].length); done.push(false); } + for (let i = 0; i < numNodes; i++) { for (const n of outEdges[i]) { inEdges[n].push(i); @@ -27,7 +28,7 @@ export function breakCycles(outEdges: number[][], chooseBreaker: (cycle: numb } } - function removeNode(node: number): void { + function removeNode (node: number): void { for (const n of outEdges[node]) { assert(inDegree[n] > 0); inDegree[n] -= 1; @@ -50,10 +51,11 @@ export function breakCycles(outEdges: number[][], chooseBreaker: (cycle: numb for (;;) { const i = workList.pop(); if (i !== undefined) { - if (done[i] || (inDegree[i] === 0 && outDegree[i] === 0)) { + if (done[i] || inDegree[i] === 0 && outDegree[i] === 0) { done[i] = true; continue; } + assert(inDegree[i] === 0 || outDegree[i] === 0, "Can't have nodes in the worklist with in and out edges"); removeNode(i); @@ -82,6 +84,7 @@ export function breakCycles(outEdges: number[][], chooseBreaker: (cycle: numb if (maybeEdge === undefined) { return panic("Presumed cycle is not a cycle"); } + const maybeFirst = path.indexOf(maybeEdge); if (maybeFirst === undefined) { // No cycle yet, continue @@ -93,11 +96,12 @@ export function breakCycles(outEdges: number[][], chooseBreaker: (cycle: numb // We found a cycle - break it const cycle = path.slice(maybeFirst); const [breakNode, info] = chooseBreaker(cycle); - assert(cycle.indexOf(breakNode) >= 0, "Breaker chose an invalid node"); + assert(cycle.includes(breakNode), "Breaker chose an invalid node"); removeNode(breakNode); results.push([breakNode, info]); break; } + continue; } diff --git a/packages/quicktype-core/src/DateTime.ts b/packages/quicktype-core/src/DateTime.ts index 20d0340b8..899daa704 100644 --- a/packages/quicktype-core/src/DateTime.ts +++ b/packages/quicktype-core/src/DateTime.ts @@ -29,17 +29,17 @@ const DAYS = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; const TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d:\d\d)?$/i; export interface DateTimeRecognizer { - isDate(s: string): boolean; - isTime(s: string): boolean; - isDateTime(s: string): boolean; + isDate: (s: string) => boolean; + isDateTime: (s: string) => boolean; + isTime: (s: string) => boolean; } const DATE_TIME_SEPARATOR = /t|\s/i; export class DefaultDateTimeRecognizer implements DateTimeRecognizer { - isDate(str: string) { + isDate (str: string) { // full-date from http://tools.ietf.org/html/rfc3339#section-5.6 - const matches = str.match(DATE); + const matches = DATE.exec(str); if (matches === null) return false; const month = +matches[2]; @@ -47,8 +47,8 @@ export class DefaultDateTimeRecognizer implements DateTimeRecognizer { return month >= 1 && month <= 12 && day >= 1 && day <= DAYS[month]; } - isTime(str: string): boolean { - const matches = str.match(TIME); + isTime (str: string): boolean { + const matches = TIME.exec(str); if (matches === null) return false; const hour = +matches[1]; @@ -57,7 +57,7 @@ export class DefaultDateTimeRecognizer implements DateTimeRecognizer { return hour <= 23 && minute <= 59 && second <= 59; } - isDateTime(str: string): boolean { + isDateTime (str: string): boolean { // http://tools.ietf.org/html/rfc3339#section-5.6 const dateTime = str.split(DATE_TIME_SEPARATOR); return dateTime.length === 2 && this.isDate(dateTime[0]) && this.isTime(dateTime[1]); diff --git a/packages/quicktype-core/src/DeclarationIR.ts b/packages/quicktype-core/src/DeclarationIR.ts index 8b36dbd51..2a42f716f 100644 --- a/packages/quicktype-core/src/DeclarationIR.ts +++ b/packages/quicktype-core/src/DeclarationIR.ts @@ -1,7 +1,7 @@ import { setUnionInto, setFilter, iterableFirst, setSubtract, setIntersect } from "collection-utils"; -import { TypeGraph } from "./TypeGraph"; -import { Type } from "./Type"; +import { type TypeGraph } from "./TypeGraph"; +import { type Type } from "./Type"; import { panic, defined, assert } from "./support/Support"; import { Graph } from "./Graph"; import { messageError } from "./Messages"; @@ -14,41 +14,43 @@ export interface Declaration { } export class DeclarationIR { - readonly declarations: ReadonlyArray; + readonly declarations: readonly Declaration[]; - constructor(declarations: Iterable, readonly forwardedTypes: Set) { + constructor (declarations: Iterable, readonly forwardedTypes: Set) { this.declarations = Array.from(declarations); } } -function findBreaker( +function findBreaker ( t: Type, - path: ReadonlyArray, - canBreak: ((t: Type) => boolean) | undefined + path: readonly Type[], + canBreak: ((t: Type) => boolean) | undefined, ): Type | undefined { const index = path.indexOf(t); if (index < 0) return undefined; if (canBreak === undefined) { return path[index]; } + const potentialBreakers = path.slice(0, index + 1).reverse(); const maybeBreaker = potentialBreakers.find(canBreak); if (maybeBreaker === undefined) { return panic("Found a cycle that cannot be broken"); } + return maybeBreaker; } -export function cycleBreakerTypesForGraph( +export function cycleBreakerTypesForGraph ( graph: TypeGraph, isImplicitCycleBreaker: (t: Type) => boolean, - canBreakCycles: (t: Type) => boolean + canBreakCycles: (t: Type) => boolean, ): Set { const visitedTypes = new Set(); const cycleBreakerTypes = new Set(); const queue: Type[] = Array.from(graph.topLevels.values()); - function visit(t: Type, path: Type[]): void { + function visit (t: Type, path: Type[]): void { if (visitedTypes.has(t)) return; if (isImplicitCycleBreaker(t)) { @@ -83,11 +85,11 @@ export function cycleBreakerTypesForGraph( return cycleBreakerTypes; } -export function declarationsForGraph( +export function declarationsForGraph ( typeGraph: TypeGraph, canBeForwardDeclared: ((t: Type) => boolean) | undefined, childrenOfType: (t: Type) => ReadonlySet, - needsDeclaration: (t: Type) => boolean + needsDeclaration: (t: Type) => boolean, ): DeclarationIR { /* function nodeTitle(t: Type): string { @@ -108,9 +110,9 @@ export function declarationsForGraph( const forwardedTypes = new Set(); const visitedComponents = new Set>(); - function processGraph(graph: Graph, _writeComponents: boolean): void { + function processGraph (graph: Graph, _writeComponents: boolean): void { const componentsGraph = graph.stronglyConnectedComponents(); - function visitComponent(component: ReadonlySet): void { + function visitComponent (component: ReadonlySet): void { if (visitedComponents.has(component)) return; visitedComponents.add(component); @@ -147,6 +149,7 @@ export function declarationsForGraph( for (const t of declarationNeeded) { declarations.push({ kind: "define", type: t }); } + return; } @@ -160,9 +163,11 @@ export function declarationsForGraph( if (forwardDeclarable.size === 0) { return messageError("IRNoForwardDeclarableTypeInCycle", {}); } + for (const t of forwardDeclarable) { declarations.push({ kind: "forward", type: t }); } + setUnionInto(forwardedTypes, forwardDeclarable); const rest = setSubtract(component, forwardDeclarable); const restGraph = new Graph(rest, true, t => setIntersect(childrenOfType(t), rest)); @@ -170,6 +175,7 @@ export function declarationsForGraph( for (const t of forwardDeclarable) { declarations.push({ kind: "define", type: t }); } + return; } diff --git a/packages/quicktype-core/src/GatherNames.ts b/packages/quicktype-core/src/GatherNames.ts index 40d1f4b05..85bbeb5ca 100644 --- a/packages/quicktype-core/src/GatherNames.ts +++ b/packages/quicktype-core/src/GatherNames.ts @@ -1,8 +1,9 @@ import * as pluralize from "pluralize"; import { setUnion, setMap, setSortBy } from "collection-utils"; -import { TypeGraph } from "./TypeGraph"; -import { Type, ObjectType } from "./Type"; +import { type TypeGraph } from "./TypeGraph"; +import { type Type} from "./Type"; +import { ObjectType } from "./Type"; import { matchCompoundType, nullableFromUnion } from "./TypeUtils"; import { TypeNames, namesTypeAttributeKind, TooManyTypeNames, tooManyNamesThreshold } from "./attributes/TypeNames"; import { defined, panic, assert } from "./support/Support"; @@ -10,29 +11,32 @@ import { transformationForType } from "./Transformers"; class UniqueQueue { private readonly _present = new Set(); - private _queue: (T | undefined)[] = []; + + private _queue: Array = []; + private _front = 0; - get size(): number { + get size (): number { return this._queue.length - this._front; } - get isEmpty(): boolean { + get isEmpty (): boolean { return this.size <= 0; } - push(v: T): void { + push (v: T): void { if (this._present.has(v)) return; this._queue.push(v); this._present.add(v); } - unshift(): T { + unshift (): T { assert(!this.isEmpty, "Trying to unshift from an empty queue"); const v = this._queue[this._front]; if (v === undefined) { return panic("Value should have been present in queue"); } + this._queue[this._front] = undefined; this._front += 1; this._present.delete(v); @@ -82,8 +86,8 @@ class UniqueQueue { // step 1, and its alternatives to a union of its direct and ancestor // alternatives, gathered in steps 2 and 3. -export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: boolean): void { - function setNames(t: Type, tn: TypeNames): void { +export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: boolean): void { + function setNames (t: Type, tn: TypeNames): void { graph.attributeStore.set(namesTypeAttributeKind, t, tn); } @@ -99,7 +103,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: // null means there are too many const namesForType = new Map | null>(); - function addNames(t: Type, names: ReadonlySet | null) { + function addNames (t: Type, names: ReadonlySet | null) { // Always use the type's given names if it has some if (t.hasNames) { const originalNames = t.getNames(); @@ -123,6 +127,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: if (newNames !== null && newNames.size >= tooManyNamesThreshold) { newNames = null; } + namesForType.set(t, newNames); const transformation = transformationForType(t); @@ -173,7 +178,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: for (const memberType of members) { addNames(memberType, names); } - } + }, ); } } @@ -193,9 +198,9 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: const ancestorAlternativesForType = new Map | null>(); const pairsProcessed = new Map>(); - function addAlternatives( + function addAlternatives ( existing: ReadonlySet | undefined, - alternatives: string[] + alternatives: string[], ): ReadonlySet | undefined | null { if (alternatives.length === 0) { return existing; @@ -204,14 +209,16 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: if (existing === undefined) { existing = new Set(); } + existing = setUnion(existing, alternatives); if (existing.size < tooManyNamesThreshold) { return existing; } + return null; } - function processType(ancestor: Type | undefined, t: Type, alternativeSuffix: string | undefined) { + function processType (ancestor: Type | undefined, t: Type, alternativeSuffix: string | undefined) { const names = defined(namesForType.get(t)); let processedEntry = pairsProcessed.get(ancestor); @@ -263,6 +270,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: if (ancestorAlternatives !== undefined) { ancestorAlternativesForType.set(t, ancestorAlternatives); } + if (directAlternatives !== undefined) { directAlternativesForType.set(t, directAlternatives); } @@ -294,7 +302,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: for (const memberType of members) { processType(ancestorForMembers, memberType, undefined); } - } + }, ); } } @@ -310,6 +318,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: directAlternativesForType.set(t, null); continue; } + let alternatives = directAlternativesForType.get(t); if (alternatives === null) continue; if (alternatives === undefined) { @@ -318,7 +327,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: alternatives = setUnion( alternatives, - setMap(names, name => `${name}_${t.kind}`) + setMap(names, name => `${name}_${t.kind}`), ); directAlternativesForType.set(t, alternatives); } @@ -343,6 +352,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: } else { alternatives = new Set(); } + if (ancestorAlternatives !== null && ancestorAlternatives !== undefined) { alternatives = setUnion(alternatives, ancestorAlternatives); } diff --git a/packages/quicktype-core/src/Graph.ts b/packages/quicktype-core/src/Graph.ts index fcff0a56a..5bcf6ba87 100644 --- a/packages/quicktype-core/src/Graph.ts +++ b/packages/quicktype-core/src/Graph.ts @@ -2,7 +2,7 @@ import { setMap } from "collection-utils"; import { defined, repeated, assert, repeatedCall } from "./support/Support"; -function countComponentGraphNodes(components: number[][]): number { +function countComponentGraphNodes (components: number[][]): number { if (components.length === 0) return 0; let largest = -1; @@ -22,7 +22,7 @@ function countComponentGraphNodes(components: number[][]): number { } // https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm -function stronglyConnectedComponents(successors: number[][]): number[][] { +function stronglyConnectedComponents (successors: number[][]): number[][] { let index = 0; const stack: number[] = []; const numNodes = successors.length; @@ -31,7 +31,7 @@ function stronglyConnectedComponents(successors: number[][]): number[][] { const onStack: boolean[] = repeated(numNodes, false); const sccs: number[][] = []; - function strongconnect(v: number): void { + function strongconnect (v: number): void { // Set the depth index for v to the smallest unused index indexes[v] = index; lowLinks[v] = index; @@ -64,6 +64,7 @@ function stronglyConnectedComponents(successors: number[][]): number[][] { onStack[w] = false; scc.push(w); } while (w !== v); + sccs.push(scc); } } @@ -79,7 +80,7 @@ function stronglyConnectedComponents(successors: number[][]): number[][] { return sccs; } -function buildComponentOfNodeMap(successors: number[][], components: number[][]): number[] { +function buildComponentOfNodeMap (successors: number[][], components: number[][]): number[] { const numComponents = components.length; const numNodes = successors.length; @@ -92,10 +93,11 @@ function buildComponentOfNodeMap(successors: number[][], components: number[][]) componentOfNode[n] = c; } } + return componentOfNode; } -function buildMetaSuccessors(successors: number[][], components: number[][]): number[][] { +function buildMetaSuccessors (successors: number[][], components: number[][]): number[][] { const numComponents = components.length; const componentOfNode = buildComponentOfNodeMap(successors, components); const componentAdded: boolean[] = repeated(numComponents, false); @@ -125,7 +127,7 @@ function buildMetaSuccessors(successors: number[][], components: number[][]): nu return metaSuccessors; } -function invertEdges(successors: number[][]): number[][] { +function invertEdges (successors: number[][]): number[][] { const numNodes = successors.length; const predecessors: number[][] = repeatedCall(numNodes, () => []); @@ -138,7 +140,7 @@ function invertEdges(successors: number[][]): number[][] { return predecessors; } -function calculateInDegrees(successors: number[][]): number[] { +function calculateInDegrees (successors: number[][]): number[] { const numNodes = successors.length; const inDegrees: number[] = repeated(numNodes, 0); @@ -151,7 +153,7 @@ function calculateInDegrees(successors: number[][]): number[] { return inDegrees; } -function findRoots(successors: number[][]): number[] { +function findRoots (successors: number[][]): number[] { const numNodes = successors.length; const inDegrees = calculateInDegrees(successors); const roots: number[] = []; @@ -166,11 +168,13 @@ function findRoots(successors: number[][]): number[] { } export class Graph { - private readonly _nodes: ReadonlyArray; + private readonly _nodes: readonly T[]; + private readonly _indexByNode: ReadonlyMap; + private readonly _successors: number[][]; - constructor(nodes: Iterable, invertDirection: boolean, edges: number[][] | ((node: T) => ReadonlySet)) { + constructor (nodes: Iterable, invertDirection: boolean, edges: number[][] | ((node: T) => ReadonlySet)) { this._nodes = Array.from(nodes); this._indexByNode = new Map(this._nodes.map((n, i): [T, number] => [n, i])); let edgesArray: number[][]; @@ -183,24 +187,25 @@ export class Graph { if (invertDirection) { edgesArray = invertEdges(edgesArray); } + this._successors = edgesArray; } - get size(): number { + get size (): number { return this._nodes.length; } - get nodes(): ReadonlyArray { + get nodes (): readonly T[] { return this._nodes; } - findRoots(): ReadonlySet { + findRoots (): ReadonlySet { const roots = findRoots(this._successors); return new Set(roots.map(n => this._nodes[n])); } // The subgraph starting at `root` must be acyclic. - dfsTraversal(root: T, preOrder: boolean, process: (node: T) => void): void { + dfsTraversal (root: T, preOrder: boolean, process: (node: T) => void): void { const visited = repeated(this.size, false); const visit = (v: number): void => { @@ -223,17 +228,17 @@ export class Graph { visit(defined(this._indexByNode.get(root))); } - stronglyConnectedComponents(): Graph> { + stronglyConnectedComponents (): Graph> { const components = stronglyConnectedComponents(this._successors); const componentSuccessors = buildMetaSuccessors(this._successors, components); return new Graph( components.map(ns => setMap(ns, n => this._nodes[n])), false, - componentSuccessors + componentSuccessors, ); } - makeDot(includeNode: (n: T) => boolean, nodeLabel: (n: T) => string): string { + makeDot (includeNode: (n: T) => boolean, nodeLabel: (n: T) => string): string { const lines: string[] = []; lines.push("digraph G {"); lines.push(" ordering = out;"); diff --git a/packages/quicktype-core/src/GraphRewriting.ts b/packages/quicktype-core/src/GraphRewriting.ts index b3610ad80..e4c099fee 100644 --- a/packages/quicktype-core/src/GraphRewriting.ts +++ b/packages/quicktype-core/src/GraphRewriting.ts @@ -1,77 +1,82 @@ import { mapMap, EqualityMap } from "collection-utils"; -import { PrimitiveTypeKind, Type, ClassProperty, MaybeTypeIdentity } from "./Type"; +import { type PrimitiveTypeKind, type Type, type ClassProperty, type MaybeTypeIdentity } from "./Type"; import { combineTypeAttributesOfTypes } from "./TypeUtils"; import { - TypeGraph, - TypeRef, + type TypeGraph, + type TypeRef} from "./TypeGraph"; +import { derefTypeRef, typeAndAttributesForTypeRef, assertTypeRefGraph, typeRefIndex, - isTypeRef + isTypeRef, } from "./TypeGraph"; -import { TypeAttributes, emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; +import { type TypeAttributes} from "./attributes/TypeAttributes"; +import { emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; import { assert, panic, indentationString } from "./support/Support"; -import { TypeBuilder, StringTypeMapping } from "./TypeBuilder"; +import { type StringTypeMapping } from "./TypeBuilder"; +import { TypeBuilder } from "./TypeBuilder"; export interface TypeLookerUp { - lookupTypeRefs(typeRefs: TypeRef[], forwardingRef?: TypeRef): TypeRef | undefined; - reconstituteTypeRef(typeRef: TypeRef, attributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef; + lookupTypeRefs: (typeRefs: TypeRef[], forwardingRef?: TypeRef) => TypeRef | undefined; + reconstituteTypeRef: (typeRef: TypeRef, attributes?: TypeAttributes, forwardingRef?: TypeRef) => TypeRef; } export class TypeReconstituter { private _wasUsed = false; + private _typeRef: TypeRef | undefined = undefined; - constructor( + constructor ( private readonly _typeBuilder: TBuilder, private readonly _makeClassUnique: boolean, private readonly _typeAttributes: TypeAttributes, private readonly _forwardingRef: TypeRef | undefined, - private readonly _register: (tref: TypeRef) => void + private readonly _register: (tref: TypeRef) => void, ) {} - private builderForNewType(): TBuilder { + private builderForNewType (): TBuilder { assert(!this._wasUsed, "TypeReconstituter used more than once"); this._wasUsed = true; return this._typeBuilder; } - private builderForSetting(): TBuilder { + private builderForSetting (): TBuilder { assert(this._wasUsed && this._typeRef !== undefined, "Can't set type members before constructing a type"); return this._typeBuilder; } - getResult(): TypeRef { + getResult (): TypeRef { if (this._typeRef === undefined) { return panic("Type was not reconstituted"); } + return this._typeRef; } // FIXME: Do registration automatically. - private register(tref: TypeRef): void { + private register (tref: TypeRef): void { assert(this._typeRef === undefined, "Cannot register a type twice"); this._typeRef = tref; this._register(tref); } - private registerAndAddAttributes(tref: TypeRef): void { + private registerAndAddAttributes (tref: TypeRef): void { this._typeBuilder.addAttributes(tref, this._typeAttributes); this.register(tref); } - lookup(tref: TypeRef): TypeRef | undefined; - lookup(trefs: Iterable): ReadonlyArray | undefined; - lookup(trefs: TypeRef | Iterable): TypeRef | ReadonlyArray | undefined { + lookup (tref: TypeRef): TypeRef | undefined; + lookup (trefs: Iterable): readonly TypeRef[] | undefined; + lookup (trefs: TypeRef | Iterable): TypeRef | readonly TypeRef[] | undefined { assert(!this._wasUsed, "Cannot lookup constituents after building type"); if (isTypeRef(trefs)) { return this._typeBuilder.lookupTypeRefs([trefs], undefined, false); } else { const maybeRefs = Array.from(trefs).map(tref => this._typeBuilder.lookupTypeRefs([tref], undefined, false)); if (maybeRefs.some(tref => tref === undefined)) return undefined; - return maybeRefs as ReadonlyArray; + return maybeRefs as readonly TypeRef[]; } } @@ -85,12 +90,13 @@ export class TypeReconstituter { result.set(k, resultValues[i]); i += 1; } + return result; } - reconstitute(tref: TypeRef): TypeRef; - reconstitute(trefs: Iterable): ReadonlyArray; - reconstitute(trefs: TypeRef | Iterable): TypeRef | ReadonlyArray { + reconstitute (tref: TypeRef): TypeRef; + reconstitute (trefs: Iterable): readonly TypeRef[]; + reconstitute (trefs: TypeRef | Iterable): TypeRef | readonly TypeRef[] { assert(this._wasUsed, "Cannot reconstitute constituents before building type"); if (isTypeRef(trefs)) { return this._typeBuilder.reconstituteTypeRef(trefs); @@ -103,105 +109,106 @@ export class TypeReconstituter { return mapMap(trefs, tref => this._typeBuilder.reconstituteTypeRef(tref)); } - getPrimitiveType(kind: PrimitiveTypeKind): void { + getPrimitiveType (kind: PrimitiveTypeKind): void { this.register(this.builderForNewType().getPrimitiveType(kind, this._typeAttributes, this._forwardingRef)); } - getEnumType(cases: ReadonlySet): void { + getEnumType (cases: ReadonlySet): void { this.register(this.builderForNewType().getEnumType(this._typeAttributes, cases, this._forwardingRef)); } - getUniqueMapType(): void { + getUniqueMapType (): void { this.registerAndAddAttributes(this.builderForNewType().getUniqueMapType(this._forwardingRef)); } - getMapType(values: TypeRef): void { + getMapType (values: TypeRef): void { this.register(this.builderForNewType().getMapType(this._typeAttributes, values, this._forwardingRef)); } - getUniqueArrayType(): void { + getUniqueArrayType (): void { this.registerAndAddAttributes(this.builderForNewType().getUniqueArrayType(this._forwardingRef)); } - getArrayType(items: TypeRef): void { + getArrayType (items: TypeRef): void { this.register(this.builderForNewType().getArrayType(this._typeAttributes, items, this._forwardingRef)); } - setArrayItems(items: TypeRef): void { + setArrayItems (items: TypeRef): void { this.builderForSetting().setArrayItems(this.getResult(), items); } - makeClassProperty(tref: TypeRef, isOptional: boolean): ClassProperty { + makeClassProperty (tref: TypeRef, isOptional: boolean): ClassProperty { return this._typeBuilder.makeClassProperty(tref, isOptional); } - getObjectType(properties: ReadonlyMap, additionalProperties: TypeRef | undefined): void { + getObjectType (properties: ReadonlyMap, additionalProperties: TypeRef | undefined): void { this.register( this.builderForNewType().getUniqueObjectType( this._typeAttributes, properties, additionalProperties, - this._forwardingRef - ) + this._forwardingRef, + ), ); } - getUniqueObjectType( + getUniqueObjectType ( properties: ReadonlyMap | undefined, - additionalProperties: TypeRef | undefined + additionalProperties: TypeRef | undefined, ): void { this.register( this.builderForNewType().getUniqueObjectType( this._typeAttributes, properties, additionalProperties, - this._forwardingRef - ) + this._forwardingRef, + ), ); } - getClassType(properties: ReadonlyMap): void { + getClassType (properties: ReadonlyMap): void { if (this._makeClassUnique) { this.getUniqueClassType(false, properties); return; } + this.register(this.builderForNewType().getClassType(this._typeAttributes, properties, this._forwardingRef)); } - getUniqueClassType(isFixed: boolean, properties: ReadonlyMap | undefined): void { + getUniqueClassType (isFixed: boolean, properties: ReadonlyMap | undefined): void { this.register( - this.builderForNewType().getUniqueClassType(this._typeAttributes, isFixed, properties, this._forwardingRef) + this.builderForNewType().getUniqueClassType(this._typeAttributes, isFixed, properties, this._forwardingRef), ); } - setObjectProperties( + setObjectProperties ( properties: ReadonlyMap, - additionalProperties: TypeRef | undefined + additionalProperties: TypeRef | undefined, ): void { this.builderForSetting().setObjectProperties(this.getResult(), properties, additionalProperties); } - getUnionType(members: ReadonlySet): void { + getUnionType (members: ReadonlySet): void { this.register(this.builderForNewType().getUnionType(this._typeAttributes, members, this._forwardingRef)); } - getUniqueUnionType(): void { + getUniqueUnionType (): void { this.register( - this.builderForNewType().getUniqueUnionType(this._typeAttributes, undefined, this._forwardingRef) + this.builderForNewType().getUniqueUnionType(this._typeAttributes, undefined, this._forwardingRef), ); } - getIntersectionType(members: ReadonlySet): void { + getIntersectionType (members: ReadonlySet): void { this.register(this.builderForNewType().getIntersectionType(this._typeAttributes, members, this._forwardingRef)); } - getUniqueIntersectionType(members?: ReadonlySet): void { + getUniqueIntersectionType (members?: ReadonlySet): void { this.register( - this.builderForNewType().getUniqueIntersectionType(this._typeAttributes, members, this._forwardingRef) + this.builderForNewType().getUniqueIntersectionType(this._typeAttributes, members, this._forwardingRef), ); } - setSetOperationMembers(members: ReadonlySet): void { + setSetOperationMembers (members: ReadonlySet): void { this.builderForSetting().setSetOperationMembers(this.getResult(), members); } } @@ -210,14 +217,15 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ protected readonly reconstitutedTypes: Map = new Map(); private _lostTypeAttributes = false; + private _printIndent = 0; - constructor( + constructor ( readonly originalGraph: TypeGraph, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, graphHasProvenanceAttributes: boolean, - protected readonly debugPrint: boolean + protected readonly debugPrint: boolean, ) { super( originalGraph.serial + 1, @@ -225,13 +233,13 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ alphabetizeProperties, false, false, - graphHasProvenanceAttributes + graphHasProvenanceAttributes, ); } - withForwardingRef( + withForwardingRef ( maybeForwardingRef: TypeRef | undefined, - typeCreator: (forwardingRef: TypeRef) => TypeRef + typeCreator: (forwardingRef: TypeRef) => TypeRef, ): TypeRef { if (maybeForwardingRef !== undefined) { return typeCreator(maybeForwardingRef); @@ -243,62 +251,66 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ return actualRef; } - reconstituteType(t: Type, attributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { + reconstituteType (t: Type, attributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { return this.reconstituteTypeRef(t.typeRef, attributes, forwardingRef); } - abstract lookupTypeRefs(typeRefs: TypeRef[], forwardingRef?: TypeRef, replaceSet?: boolean): TypeRef | undefined; - protected abstract forceReconstituteTypeRef( + abstract lookupTypeRefs (typeRefs: TypeRef[], forwardingRef?: TypeRef, replaceSet?: boolean): TypeRef | undefined; + protected abstract forceReconstituteTypeRef ( originalRef: TypeRef, attributes?: TypeAttributes, maybeForwardingRef?: TypeRef ): TypeRef; - reconstituteTypeRef(originalRef: TypeRef, attributes?: TypeAttributes, maybeForwardingRef?: TypeRef): TypeRef { + reconstituteTypeRef (originalRef: TypeRef, attributes?: TypeAttributes, maybeForwardingRef?: TypeRef): TypeRef { const maybeRef = this.lookupTypeRefs([originalRef], maybeForwardingRef); if (maybeRef !== undefined) { if (attributes !== undefined) { this.addAttributes(maybeRef, attributes); } + return maybeRef; } + return this.forceReconstituteTypeRef(originalRef, attributes, maybeForwardingRef); } - reconstituteTypeAttributes(attributes: TypeAttributes): TypeAttributes { + reconstituteTypeAttributes (attributes: TypeAttributes): TypeAttributes { return mapMap(attributes, (v, a) => a.reconstitute(this, v)); } - protected assertTypeRefsToReconstitute(typeRefs: TypeRef[], forwardingRef?: TypeRef): void { + protected assertTypeRefsToReconstitute (typeRefs: TypeRef[], forwardingRef?: TypeRef): void { assert(typeRefs.length > 0, "Must have at least one type to reconstitute"); for (const originalRef of typeRefs) { assertTypeRefGraph(originalRef, this.originalGraph); } + if (forwardingRef !== undefined) { assertTypeRefGraph(forwardingRef, this.typeGraph); } } - protected changeDebugPrintIndent(delta: number): void { + protected changeDebugPrintIndent (delta: number): void { this._printIndent += delta; } - protected get debugPrintIndentation(): string { + protected get debugPrintIndentation (): string { return indentationString(this._printIndent); } - finish(): TypeGraph { + finish (): TypeGraph { for (const [name, t] of this.originalGraph.topLevels) { this.addTopLevel(name, this.reconstituteType(t)); } + return super.finish(); } - setLostTypeAttributes(): void { + setLostTypeAttributes (): void { this._lostTypeAttributes = true; } - get lostTypeAttributes(): boolean { + get lostTypeAttributes (): boolean { return this._lostTypeAttributes; } } @@ -306,20 +318,20 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { private readonly _attributeSources: Map = new Map(); - constructor( + constructor ( originalGraph: TypeGraph, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, graphHasProvenanceAttributes: boolean, private readonly _map: ReadonlyMap, - debugPrintRemapping: boolean + debugPrintRemapping: boolean, ) { super( originalGraph, stringTypeMapping, alphabetizeProperties, graphHasProvenanceAttributes, - debugPrintRemapping + debugPrintRemapping, ); for (const [source, target] of _map) { @@ -328,26 +340,27 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { maybeSources = [target]; this._attributeSources.set(target, maybeSources); } + maybeSources.push(source); } } - protected makeIdentity(_maker: () => MaybeTypeIdentity): MaybeTypeIdentity { + protected makeIdentity (_maker: () => MaybeTypeIdentity): MaybeTypeIdentity { return undefined; } - private getMapTarget(tref: TypeRef): TypeRef { + private getMapTarget (tref: TypeRef): TypeRef { const maybeType = this._map.get(derefTypeRef(tref, this.originalGraph)); if (maybeType === undefined) return tref; assert(this._map.get(maybeType) === undefined, "We have a type that's remapped to a remapped type"); return maybeType.typeRef; } - protected addForwardingIntersection(_forwardingRef: TypeRef, _tref: TypeRef): TypeRef { + protected addForwardingIntersection (_forwardingRef: TypeRef, _tref: TypeRef): TypeRef { return panic("We can't add forwarding intersections when we're removing forwarding intersections"); } - lookupTypeRefs(typeRefs: TypeRef[], forwardingRef?: TypeRef): TypeRef | undefined { + lookupTypeRefs (typeRefs: TypeRef[], forwardingRef?: TypeRef): TypeRef | undefined { assert(forwardingRef === undefined, "We can't have a forwarding ref when we remap"); this.assertTypeRefsToReconstitute(typeRefs, forwardingRef); @@ -363,10 +376,10 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { return first; } - protected forceReconstituteTypeRef( + protected forceReconstituteTypeRef ( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef { originalRef = this.getMapTarget(originalRef); @@ -389,19 +402,21 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { if (attributes === undefined) { attributes = emptyTypeAttributes; } + if (attributeSources === undefined) { attributes = combineTypeAttributes( "union", attributes, - this.reconstituteTypeAttributes(originalAttributes) + this.reconstituteTypeAttributes(originalAttributes), ); } else { attributes = combineTypeAttributes( "union", attributes, - this.reconstituteTypeAttributes(combineTypeAttributesOfTypes("union", attributeSources)) + this.reconstituteTypeAttributes(combineTypeAttributesOfTypes("union", attributeSources)), ); } + const newAttributes = attributes; const reconstituter = new TypeReconstituter( @@ -415,7 +430,7 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { this.changeDebugPrintIndent(-1); console.log(`${this.debugPrintIndentation}reconstituted ${index} as ${typeRefIndex(tref)}`); } - } + }, ); originalType.reconstitute(reconstituter, this.canonicalOrder); return reconstituter.getResult(); @@ -425,9 +440,10 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { export class GraphRewriteBuilder extends BaseGraphRewriteBuilder { private readonly _setsToReplaceByMember: Map>; + private readonly _reconstitutedUnions: EqualityMap, TypeRef> = new EqualityMap(); - constructor( + constructor ( originalGraph: TypeGraph, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, @@ -438,14 +454,14 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder typesToReplace: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef - ) => TypeRef + ) => TypeRef, ) { super( originalGraph, stringTypeMapping, alphabetizeProperties, graphHasProvenanceAttributes, - debugPrintReconstitution + debugPrintReconstitution, ); this._setsToReplaceByMember = new Map(); @@ -459,19 +475,19 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder } } - registerUnion(typeRefs: TypeRef[], reconstituted: TypeRef): void { + registerUnion (typeRefs: TypeRef[], reconstituted: TypeRef): void { const set = new Set(typeRefs); assert(!this._reconstitutedUnions.has(set), "Cannot register reconstituted set twice"); this._reconstitutedUnions.set(set, reconstituted); } - private replaceSet(typesToReplace: ReadonlySet, maybeForwardingRef: TypeRef | undefined): TypeRef { + private replaceSet (typesToReplace: ReadonlySet, maybeForwardingRef: TypeRef | undefined): TypeRef { return this.withForwardingRef(maybeForwardingRef, forwardingRef => { if (this.debugPrint) { console.log( `${this.debugPrintIndentation}replacing set ${Array.from(typesToReplace) .map(t => t.index.toString()) - .join(",")} as ${typeRefIndex(forwardingRef)}` + .join(",")} as ${typeRefIndex(forwardingRef)}`, ); this.changeDebugPrintIndent(1); } @@ -482,6 +498,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder this.reconstitutedTypes.set(index, forwardingRef); this._setsToReplaceByMember.delete(index); } + const result = this._replacer(typesToReplace, this, forwardingRef); assert(result === forwardingRef, "The forwarding ref got lost when replacing"); @@ -490,7 +507,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder console.log( `${this.debugPrintIndentation}replaced set ${Array.from(typesToReplace) .map(t => t.index.toString()) - .join(",")} as ${typeRefIndex(forwardingRef)}` + .join(",")} as ${typeRefIndex(forwardingRef)}`, ); } @@ -498,10 +515,10 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder }); } - protected forceReconstituteTypeRef( + protected forceReconstituteTypeRef ( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef { const [originalType, originalAttributes] = typeAndAttributesForTypeRef(originalRef, this.originalGraph); const index = typeRefIndex(originalRef); @@ -517,7 +534,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder attributes = combineTypeAttributes( "union", attributes, - this.reconstituteTypeAttributes(originalAttributes) + this.reconstituteTypeAttributes(originalAttributes), ); } @@ -558,7 +575,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder // If the union of these type refs have been, or are supposed to be, reconstituted to // one target type, return it. Otherwise return undefined. - lookupTypeRefs(typeRefs: TypeRef[], forwardingRef?: TypeRef, replaceSet = true): TypeRef | undefined { + lookupTypeRefs (typeRefs: TypeRef[], forwardingRef?: TypeRef, replaceSet = true): TypeRef | undefined { this.assertTypeRefsToReconstitute(typeRefs, forwardingRef); // Check whether we have already reconstituted them. That means ensuring @@ -572,6 +589,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder break; } } + if (allEqual) { return this.forwardIfNecessary(forwardingRef, maybeRef); } @@ -588,11 +606,13 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder if (maybeSet === undefined) { return undefined; } + for (let i = 1; i < typeRefs.length; i++) { if (this._setsToReplaceByMember.get(typeRefIndex(typeRefs[i])) !== maybeSet) { return undefined; } } + // Yes, this set is requested to be replaced, so do it. if (!replaceSet) return undefined; return this.replaceSet(maybeSet, forwardingRef); diff --git a/packages/quicktype-core/src/MakeTransformations.ts b/packages/quicktype-core/src/MakeTransformations.ts index 4e44d89f5..0b98b390f 100644 --- a/packages/quicktype-core/src/MakeTransformations.ts +++ b/packages/quicktype-core/src/MakeTransformations.ts @@ -1,21 +1,26 @@ import { setFilter, iterableFirst, mapMapEntries, withDefault, iterableSome, arraySortByInto } from "collection-utils"; -import { TypeGraph, TypeRef, typeRefIndex } from "./TypeGraph"; -import { TargetLanguage } from "./TargetLanguage"; +import { type TypeGraph, type TypeRef} from "./TypeGraph"; +import { typeRefIndex } from "./TypeGraph"; +import { type TargetLanguage } from "./TargetLanguage"; +import { + type TypeKind, + type Type, + type PrimitiveType, + type PrimitiveStringTypeKind, +} from "./Type"; import { UnionType, - TypeKind, EnumType, - Type, ArrayType, - PrimitiveType, isNumberTypeKind, isPrimitiveStringTypeKind, targetTypeKindForTransformedStringTypeKind, - PrimitiveStringTypeKind } from "./Type"; -import { GraphRewriteBuilder } from "./GraphRewriting"; +import { type GraphRewriteBuilder } from "./GraphRewriting"; import { defined, assert, panic } from "./support/Support"; +import { + type Transformer} from "./Transformers"; import { UnionInstantiationTransformer, DecodingChoiceTransformer, @@ -24,39 +29,40 @@ import { StringMatchTransformer, StringProducerTransformer, ChoiceTransformer, - Transformer, DecodingTransformer, ParseStringTransformer, ArrayDecodingTransformer, MinMaxLengthCheckTransformer, - MinMaxValueTransformer + MinMaxValueTransformer, } from "./Transformers"; -import { TypeAttributes, emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; +import { type TypeAttributes} from "./attributes/TypeAttributes"; +import { emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; import { StringTypes } from "./attributes/StringTypes"; -import { RunContext } from "./Run"; +import { type RunContext } from "./Run"; import { minMaxLengthForType, minMaxValueForType } from "./attributes/Constraints"; -function transformationAttributes( +function transformationAttributes ( graph: TypeGraph, reconstitutedTargetType: TypeRef, transformer: Transformer, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeAttributes { const transformation = new Transformation(graph, reconstitutedTargetType, transformer); if (debugPrintTransformations) { console.log(`transformation for ${typeRefIndex(reconstitutedTargetType)}:`); transformation.debugPrint(); - console.log(`reverse:`); + console.log("reverse:"); transformation.reverse.debugPrint(); } + return transformationTypeAttributeKind.makeAttributes(transformation); } -function makeEnumTransformer( +function makeEnumTransformer ( graph: TypeGraph, enumType: EnumType, stringType: TypeRef, - continuation?: Transformer + continuation?: Transformer, ): Transformer { const sortedCases = Array.from(enumType.cases).sort(); const caseTransformers = sortedCases.map( @@ -65,18 +71,18 @@ function makeEnumTransformer( graph, stringType, new StringProducerTransformer(graph, stringType, continuation, c), - c - ) + c, + ), ); return new ChoiceTransformer(graph, stringType, caseTransformers); } -function replaceUnion( +function replaceUnion ( union: UnionType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, transformedTypes: Set, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const graph = builder.typeGraph; @@ -85,7 +91,7 @@ function replaceUnion( // Type attributes that we lost during reconstitution. let additionalAttributes = emptyTypeAttributes; - function reconstituteMember(t: Type): TypeRef { + function reconstituteMember (t: Type): TypeRef { // Special handling for some transformed string type kinds: The type in // the union must be the target type, so if one already exists, use that // one, otherwise make a new one. @@ -97,9 +103,11 @@ function replaceUnion( if (targetTypeMember !== undefined) { return builder.reconstituteType(targetTypeMember); } + return builder.getPrimitiveType(targetTypeKind); } } + return builder.reconstituteType(t); } @@ -115,16 +123,16 @@ function replaceUnion( ? builder.getUnionType(union.getAttributes(), reconstitutedMemberSet) : defined(iterableFirst(reconstitutedMemberSet)); - function memberForKind(kind: TypeKind) { + function memberForKind (kind: TypeKind) { return defined(reconstitutedMembersByKind.get(kind)); } - function consumer(memberTypeRef: TypeRef): Transformer | undefined { + function consumer (memberTypeRef: TypeRef): Transformer | undefined { if (!haveUnion) return undefined; return new UnionInstantiationTransformer(graph, memberTypeRef); } - function transformerForKind(kind: TypeKind) { + function transformerForKind (kind: TypeKind) { const member = union.findMember(kind); if (member === undefined) return undefined; const memberTypeRef = memberForKind(kind); @@ -132,20 +140,22 @@ function replaceUnion( } let maybeStringType: TypeRef | undefined = undefined; - function getStringType(): TypeRef { + function getStringType (): TypeRef { if (maybeStringType === undefined) { maybeStringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); } + return maybeStringType; } - function transformerForStringType(t: Type): Transformer | undefined { + function transformerForStringType (t: Type): Transformer | undefined { const memberRef = memberForKind(t.kind); if (t.kind === "string") { const minMax = minMaxLengthForType(t); if (minMax === undefined) { return consumer(memberRef); } + const [min, max] = minMax; return new MinMaxLengthCheckTransformer(graph, getStringType(), consumer(memberRef), min, max); } else if (t instanceof EnumType && transformedTypes.has(t)) { @@ -169,8 +179,8 @@ function replaceUnion( new ChoiceTransformer( graph, getStringType(), - stringTypes.map(t => defined(transformerForStringType(t))) - ) + stringTypes.map(t => defined(transformerForStringType(t))), + ), ); } @@ -178,7 +188,7 @@ function replaceUnion( const transformerForMap = transformerForKind("map"); assert( transformerForClass === undefined || transformerForMap === undefined, - "Can't have both class and map in a transformed union" + "Can't have both class and map in a transformed union", ); const transformerForObject = transformerForClass !== undefined ? transformerForClass : transformerForMap; @@ -191,21 +201,21 @@ function replaceUnion( transformerForKind("bool"), transformerForString, transformerForKind("array"), - transformerForObject + transformerForObject, ); const attributes = transformationAttributes(graph, reconstitutedTargetType, transformer, debugPrintTransformations); return builder.getPrimitiveType( "any", combineTypeAttributes("union", attributes, additionalAttributes), - forwardingRef + forwardingRef, ); } -function replaceArray( +function replaceArray ( arrayType: ArrayType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const anyType = builder.getPrimitiveType("any"); const anyArrayType = builder.getArrayType(emptyTypeAttributes, anyType); @@ -215,74 +225,74 @@ function replaceArray( anyArrayType, undefined, reconstitutedItems, - new DecodingTransformer(builder.typeGraph, anyType, undefined) + new DecodingTransformer(builder.typeGraph, anyType, undefined), ); const reconstitutedArray = builder.getArrayType( builder.reconstituteTypeAttributes(arrayType.getAttributes()), - reconstitutedItems + reconstitutedItems, ); const attributes = transformationAttributes( builder.typeGraph, reconstitutedArray, transformer, - debugPrintTransformations + debugPrintTransformations, ); return builder.getArrayType(attributes, anyType, forwardingRef); } -function replaceEnum( +function replaceEnum ( enumType: EnumType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); const transformer = new DecodingTransformer( builder.typeGraph, stringType, - makeEnumTransformer(builder.typeGraph, enumType, stringType) + makeEnumTransformer(builder.typeGraph, enumType, stringType), ); const reconstitutedEnum = builder.getEnumType(enumType.getAttributes(), enumType.cases); const attributes = transformationAttributes( builder.typeGraph, reconstitutedEnum, transformer, - debugPrintTransformations + debugPrintTransformations, ); return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } -function replaceNumber( +function replaceNumber ( t: PrimitiveType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); const [min, max] = defined(minMaxValueForType(t)); const transformer = new DecodingTransformer( builder.typeGraph, stringType, - new MinMaxValueTransformer(builder.typeGraph, stringType, undefined, min, max) + new MinMaxValueTransformer(builder.typeGraph, stringType, undefined, min, max), ); const reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); const attributes = transformationAttributes( builder.typeGraph, builder.getPrimitiveType("double", reconstitutedAttributes, undefined), transformer, - debugPrintTransformations + debugPrintTransformations, ); return builder.getPrimitiveType("double", attributes, forwardingRef); } -function replaceString( +function replaceString ( t: PrimitiveType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const [min, max] = defined(minMaxLengthForType(t)); const reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); @@ -290,23 +300,23 @@ function replaceString( const transformer = new DecodingTransformer( builder.typeGraph, stringType, - new MinMaxLengthCheckTransformer(builder.typeGraph, stringType, undefined, min, max) + new MinMaxLengthCheckTransformer(builder.typeGraph, stringType, undefined, min, max), ); const attributes = transformationAttributes( builder.typeGraph, builder.getStringType(reconstitutedAttributes, undefined), transformer, - debugPrintTransformations + debugPrintTransformations, ); return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } -function replaceTransformedStringType( +function replaceTransformedStringType ( t: PrimitiveType, kind: PrimitiveStringTypeKind, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); const targetTypeKind = withDefault(targetTypeKindForTransformedStringTypeKind(kind), kind); @@ -314,18 +324,18 @@ function replaceTransformedStringType( const transformer = new DecodingTransformer( builder.typeGraph, stringType, - new ParseStringTransformer(builder.typeGraph, stringType, undefined) + new ParseStringTransformer(builder.typeGraph, stringType, undefined), ); const attributes = transformationAttributes( builder.typeGraph, builder.getPrimitiveType(targetTypeKind, reconstitutedAttributes), transformer, - debugPrintTransformations + debugPrintTransformations, ); return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } -export function makeTransformations(ctx: RunContext, graph: TypeGraph, targetLanguage: TargetLanguage): TypeGraph { +export function makeTransformations (ctx: RunContext, graph: TypeGraph, targetLanguage: TargetLanguage): TypeGraph { const transformedTypes = setFilter(graph.allTypesUnordered(), t => { if (targetLanguage.needsTransformerForType(t)) return true; if (!(t instanceof UnionType)) return false; @@ -334,36 +344,42 @@ export function makeTransformations(ctx: RunContext, graph: TypeGraph, targetLan return iterableSome(stringMembers, m => targetLanguage.needsTransformerForType(m)); }); - function replace( + function replace ( setOfOneUnion: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { const t = defined(iterableFirst(setOfOneUnion)); if (t instanceof UnionType) { return replaceUnion(t, builder, forwardingRef, transformedTypes, ctx.debugPrintTransformations); } + if (t instanceof ArrayType) { return replaceArray(t, builder, forwardingRef, ctx.debugPrintTransformations); } + if (t instanceof EnumType) { return replaceEnum(t, builder, forwardingRef, ctx.debugPrintTransformations); } + if (t.kind === "string") { return replaceString(t as PrimitiveType, builder, forwardingRef, ctx.debugPrintTransformations); } + if (isNumberTypeKind(t.kind)) { return replaceNumber(t as PrimitiveType, builder, forwardingRef, ctx.debugPrintTransformations); } + if (isPrimitiveStringTypeKind(t.kind)) { return replaceTransformedStringType( t as PrimitiveType, t.kind, builder, forwardingRef, - ctx.debugPrintTransformations + ctx.debugPrintTransformations, ); } + return panic(`Cannot make transformation for type ${t.kind}`); } @@ -374,6 +390,6 @@ export function makeTransformations(ctx: RunContext, graph: TypeGraph, targetLan false, groups, ctx.debugPrintReconstitution, - replace + replace, ); } diff --git a/packages/quicktype-core/src/MarkovChain.ts b/packages/quicktype-core/src/MarkovChain.ts index 1c1b730a6..85bd62b4d 100644 --- a/packages/quicktype-core/src/MarkovChain.ts +++ b/packages/quicktype-core/src/MarkovChain.ts @@ -3,25 +3,26 @@ import { encodedMarkovChain } from "./EncodedMarkovChain"; // This must be null, not undefined, because we read it from JSON. export type SubTrie = number | null | Trie; -export type Trie = { - count: number; +export interface Trie { arr: SubTrie[]; -}; + count: number; +} -export type MarkovChain = { - trie: Trie; +export interface MarkovChain { depth: number; -}; + trie: Trie; +} -function makeTrie(): Trie { +function makeTrie (): Trie { const arr: SubTrie[] = []; for (let i = 0; i < 128; i++) { arr.push(null); } + return { count: 0, arr }; } -function lookup(t: Trie, seq: string, i: number): Trie | number | undefined { +function lookup (t: Trie, seq: string, i: number): Trie | number | undefined { if (i >= seq.length) { return t; } @@ -35,6 +36,7 @@ function lookup(t: Trie, seq: string, i: number): Trie | number | undefined { if (n === null) { return undefined; } + if (typeof n === "object") { return lookup(n, seq, i + 1); } else { @@ -42,7 +44,7 @@ function lookup(t: Trie, seq: string, i: number): Trie | number | undefined { } } -function increment(t: Trie, seq: string, i: number): void { +function increment (t: Trie, seq: string, i: number): void { let first = seq.charCodeAt(i); if (first >= 128) { first = 0; @@ -52,12 +54,14 @@ function increment(t: Trie, seq: string, i: number): void { if (typeof t !== "object") { return panic("Malformed trie"); } + let n = t.arr[first]; if (n === null) { n = 0; } else if (typeof n === "object") { return panic("Malformed trie"); } + t.arr[first] = n + 1; t.count += 1; return; @@ -67,13 +71,15 @@ function increment(t: Trie, seq: string, i: number): void { if (st === null) { t.arr[first] = st = makeTrie(); } + if (typeof st !== "object") { return panic("Malformed trie"); } - return increment(st, seq, i + 1); + + increment(st, seq, i + 1); } -export function train(lines: string[], depth: number): MarkovChain { +export function train (lines: string[], depth: number): MarkovChain { const trie = makeTrie(); for (const l of lines) { for (let i = depth; i <= l.length; i++) { @@ -84,15 +90,16 @@ export function train(lines: string[], depth: number): MarkovChain { return { trie, depth }; } -export function load(): MarkovChain { +export function load (): MarkovChain { return JSON.parse(inflateBase64(encodedMarkovChain)); } -export function evaluateFull(mc: MarkovChain, word: string): [number, number[]] { +export function evaluateFull (mc: MarkovChain, word: string): [number, number[]] { const { trie, depth } = mc; if (word.length < depth) { return [1, []]; } + let p = 1; const scores: number[] = []; for (let i = depth; i <= word.length; i++) { @@ -100,38 +107,44 @@ export function evaluateFull(mc: MarkovChain, word: string): [number, number[]] if (typeof cp === "object") { return panic("Did we mess up the depth?"); } + if (cp === undefined) { cp = 0.0001; } + scores.push(cp); p = p * cp; } + return [Math.pow(p, 1 / (word.length - depth + 1)), scores]; } -export function evaluate(mc: MarkovChain, word: string): number { +export function evaluate (mc: MarkovChain, word: string): number { return evaluateFull(mc, word)[0]; } -function randomInt(lower: number, upper: number) { +function randomInt (lower: number, upper: number) { const range = upper - lower; return lower + Math.floor(Math.random() * range); } -export function generate(mc: MarkovChain, state: string, unseenWeight: number): string { +export function generate (mc: MarkovChain, state: string, unseenWeight: number): string { assert(state.length === mc.depth - 1, "State and chain length don't match up"); const t = lookup(mc.trie, state, 0); if (typeof t === "number") { return panic("Wrong depth?"); } + if (t === undefined) { return String.fromCharCode(randomInt(32, 127)); } - const counts = t.arr.map((x, i) => (x === null ? (i === 0 ? 0 : unseenWeight) : (x as number))); + + const counts = t.arr.map((x, i) => x === null ? i === 0 ? 0 : unseenWeight : (x as number)); let n = 0; for (const c of counts) { n += c; } + const r = randomInt(0, n); let sum = 0; for (let i = 0; i < counts.length; i++) { @@ -140,14 +153,15 @@ export function generate(mc: MarkovChain, state: string, unseenWeight: number): return String.fromCharCode(i); } } + return panic("We screwed up bookkeeping, or randomInt"); } -function testWord(mc: MarkovChain, word: string): void { +function testWord (mc: MarkovChain, word: string): void { console.log(`"${word}": ${evaluate(mc, word)}`); } -export function test(): void { +export function test (): void { const mc = load(); testWord(mc, "url"); @@ -171,6 +185,6 @@ export function test(): void { testWord( mc, - "\ud83d\udebe \ud83c\udd92 \ud83c\udd93 \ud83c\udd95 \ud83c\udd96 \ud83c\udd97 \ud83c\udd99 \ud83c\udfe7" + "\ud83d\udebe \ud83c\udd92 \ud83c\udd93 \ud83c\udd95 \ud83c\udd96 \ud83c\udd97 \ud83c\udd99 \ud83c\udfe7", ); } diff --git a/packages/quicktype-core/src/Messages.ts b/packages/quicktype-core/src/Messages.ts index d740163ec..082c3ce40 100644 --- a/packages/quicktype-core/src/Messages.ts +++ b/packages/quicktype-core/src/Messages.ts @@ -1,85 +1,85 @@ -import { StringMap } from "./support/Support"; -import { Ref } from "./input/JSONSchemaInput"; +import { type StringMap } from "./support/Support"; +import { type Ref } from "./input/JSONSchemaInput"; export type ErrorProperties = - | { kind: "InternalError"; properties: { message: string } } + | { kind: "InternalError", properties: { message: string, }, } // Misc | { - kind: "MiscJSONParseError"; - properties: { description: string; address: string; message: string }; - } - | { kind: "MiscReadError"; properties: { fileOrURL: string; message: string } } - | { kind: "MiscUnicodeHighSurrogateWithoutLowSurrogate"; properties: {} } - | { kind: "MiscInvalidMinMaxConstraint"; properties: { min: number; max: number } } + kind: "MiscJSONParseError", + properties: { address: string, description: string, message: string, }, + } + | { kind: "MiscReadError", properties: { fileOrURL: string, message: string, }, } + | { kind: "MiscUnicodeHighSurrogateWithoutLowSurrogate", properties: {}, } + | { kind: "MiscInvalidMinMaxConstraint", properties: { max: number, min: number, }, } // Inference - | { kind: "InferenceJSONReferenceNotRooted"; properties: { reference: string } } - | { kind: "InferenceJSONReferenceToUnion"; properties: { reference: string } } - | { kind: "InferenceJSONReferenceWrongProperty"; properties: { reference: string } } - | { kind: "InferenceJSONReferenceInvalidArrayIndex"; properties: { reference: string } } + | { kind: "InferenceJSONReferenceNotRooted", properties: { reference: string, }, } + | { kind: "InferenceJSONReferenceToUnion", properties: { reference: string, }, } + | { kind: "InferenceJSONReferenceWrongProperty", properties: { reference: string, }, } + | { kind: "InferenceJSONReferenceInvalidArrayIndex", properties: { reference: string, }, } // JSON Schema input - | { kind: "SchemaArrayIsInvalidSchema"; properties: { ref: Ref } } - | { kind: "SchemaNullIsInvalidSchema"; properties: { ref: Ref } } - | { kind: "SchemaRefMustBeString"; properties: { actual: string; ref: Ref } } - | { kind: "SchemaAdditionalTypesForbidRequired"; properties: { ref: Ref } } - | { kind: "SchemaNoTypeSpecified"; properties: { ref: Ref } } - | { kind: "SchemaInvalidType"; properties: { type: string; ref: Ref } } - | { kind: "SchemaFalseNotSupported"; properties: { ref: Ref } } - | { kind: "SchemaInvalidJSONSchemaType"; properties: { type: string; ref: Ref } } - | { kind: "SchemaRequiredMustBeStringOrStringArray"; properties: { actual: any; ref: Ref } } - | { kind: "SchemaRequiredElementMustBeString"; properties: { element: any; ref: Ref } } - | { kind: "SchemaTypeMustBeStringOrStringArray"; properties: { actual: any } } - | { kind: "SchemaTypeElementMustBeString"; properties: { element: any; ref: Ref } } - | { kind: "SchemaArrayItemsMustBeStringOrArray"; properties: { actual: any; ref: Ref } } - | { kind: "SchemaIDMustHaveAddress"; properties: { id: string; ref: Ref } } - | { kind: "SchemaWrongAccessorEntryArrayLength"; properties: { operation: string; ref: Ref } } + | { kind: "SchemaArrayIsInvalidSchema", properties: { ref: Ref, }, } + | { kind: "SchemaNullIsInvalidSchema", properties: { ref: Ref, }, } + | { kind: "SchemaRefMustBeString", properties: { actual: string, ref: Ref, }, } + | { kind: "SchemaAdditionalTypesForbidRequired", properties: { ref: Ref, }, } + | { kind: "SchemaNoTypeSpecified", properties: { ref: Ref, }, } + | { kind: "SchemaInvalidType", properties: { ref: Ref, type: string, }, } + | { kind: "SchemaFalseNotSupported", properties: { ref: Ref, }, } + | { kind: "SchemaInvalidJSONSchemaType", properties: { ref: Ref, type: string, }, } + | { kind: "SchemaRequiredMustBeStringOrStringArray", properties: { actual: any, ref: Ref, }, } + | { kind: "SchemaRequiredElementMustBeString", properties: { element: any, ref: Ref, }, } + | { kind: "SchemaTypeMustBeStringOrStringArray", properties: { actual: any, }, } + | { kind: "SchemaTypeElementMustBeString", properties: { element: any, ref: Ref, }, } + | { kind: "SchemaArrayItemsMustBeStringOrArray", properties: { actual: any, ref: Ref, }, } + | { kind: "SchemaIDMustHaveAddress", properties: { id: string, ref: Ref, }, } + | { kind: "SchemaWrongAccessorEntryArrayLength", properties: { operation: string, ref: Ref, }, } | { - kind: "SchemaSetOperationCasesIsNotArray"; - properties: { operation: string; cases: any; ref: Ref }; - } - | { kind: "SchemaMoreThanOneUnionMemberName"; properties: { names: string[] } } - | { kind: "SchemaCannotGetTypesFromBoolean"; properties: { ref: string } } - | { kind: "SchemaCannotIndexArrayWithNonNumber"; properties: { actual: string; ref: Ref } } - | { kind: "SchemaIndexNotInArray"; properties: { index: number; ref: Ref } } - | { kind: "SchemaKeyNotInObject"; properties: { key: string; ref: Ref } } - | { kind: "SchemaFetchError"; properties: { address: string; base: Ref } } - | { kind: "SchemaFetchErrorTopLevel"; properties: { address: string } } - | { kind: "SchemaFetchErrorAdditional"; properties: { address: string } } + kind: "SchemaSetOperationCasesIsNotArray", + properties: { cases: any, operation: string, ref: Ref, }, + } + | { kind: "SchemaMoreThanOneUnionMemberName", properties: { names: string[], }, } + | { kind: "SchemaCannotGetTypesFromBoolean", properties: { ref: string, }, } + | { kind: "SchemaCannotIndexArrayWithNonNumber", properties: { actual: string, ref: Ref, }, } + | { kind: "SchemaIndexNotInArray", properties: { index: number, ref: Ref, }, } + | { kind: "SchemaKeyNotInObject", properties: { key: string, ref: Ref, }, } + | { kind: "SchemaFetchError", properties: { address: string, base: Ref, }, } + | { kind: "SchemaFetchErrorTopLevel", properties: { address: string, }, } + | { kind: "SchemaFetchErrorAdditional", properties: { address: string, }, } // GraphQL input - | { kind: "GraphQLNoQueriesDefined"; properties: {} } + | { kind: "GraphQLNoQueriesDefined", properties: {}, } // Driver - | { kind: "DriverUnknownSourceLanguage"; properties: { lang: string } } - | { kind: "DriverUnknownOutputLanguage"; properties: { lang: string } } - | { kind: "DriverMoreThanOneInputGiven"; properties: { topLevel: string } } - | { kind: "DriverCannotInferNameForSchema"; properties: { uri: string } } - | { kind: "DriverNoGraphQLQueryGiven"; properties: {} } - | { kind: "DriverNoGraphQLSchemaInDir"; properties: { dir: string } } - | { kind: "DriverMoreThanOneGraphQLSchemaInDir"; properties: { dir: string } } - | { kind: "DriverSourceLangMustBeGraphQL"; properties: {} } - | { kind: "DriverGraphQLSchemaNeeded"; properties: {} } - | { kind: "DriverInputFileDoesNotExist"; properties: { filename: string } } - | { kind: "DriverCannotMixJSONWithOtherSamples"; properties: { dir: string } } - | { kind: "DriverCannotMixNonJSONInputs"; properties: { dir: string } } - | { kind: "DriverUnknownDebugOption"; properties: { option: string } } - | { kind: "DriverNoLanguageOrExtension"; properties: {} } - | { kind: "DriverCLIOptionParsingFailed"; properties: { message: string } } + | { kind: "DriverUnknownSourceLanguage", properties: { lang: string, }, } + | { kind: "DriverUnknownOutputLanguage", properties: { lang: string, }, } + | { kind: "DriverMoreThanOneInputGiven", properties: { topLevel: string, }, } + | { kind: "DriverCannotInferNameForSchema", properties: { uri: string, }, } + | { kind: "DriverNoGraphQLQueryGiven", properties: {}, } + | { kind: "DriverNoGraphQLSchemaInDir", properties: { dir: string, }, } + | { kind: "DriverMoreThanOneGraphQLSchemaInDir", properties: { dir: string, }, } + | { kind: "DriverSourceLangMustBeGraphQL", properties: {}, } + | { kind: "DriverGraphQLSchemaNeeded", properties: {}, } + | { kind: "DriverInputFileDoesNotExist", properties: { filename: string, }, } + | { kind: "DriverCannotMixJSONWithOtherSamples", properties: { dir: string, }, } + | { kind: "DriverCannotMixNonJSONInputs", properties: { dir: string, }, } + | { kind: "DriverUnknownDebugOption", properties: { option: string, }, } + | { kind: "DriverNoLanguageOrExtension", properties: {}, } + | { kind: "DriverCLIOptionParsingFailed", properties: { message: string, }, } // IR - | { kind: "IRNoForwardDeclarableTypeInCycle"; properties: {} } - | { kind: "IRTypeAttributesNotPropagated"; properties: { count: number; indexes: number[] } } - | { kind: "IRNoEmptyUnions"; properties: {} } + | { kind: "IRNoForwardDeclarableTypeInCycle", properties: {}, } + | { kind: "IRTypeAttributesNotPropagated", properties: { count: number, indexes: number[], }, } + | { kind: "IRNoEmptyUnions", properties: {}, } // Rendering - | { kind: "RendererUnknownOptionValue"; properties: { value: string; name: string } } + | { kind: "RendererUnknownOptionValue", properties: { name: string, value: string, }, } // TypeScript input - | { kind: "TypeScriptCompilerError"; properties: { message: string } }; + | { kind: "TypeScriptCompilerError", properties: { message: string, }, }; -export type ErrorKinds = ErrorProperties extends { kind: infer K } ? K : never; +export type ErrorKinds = ErrorProperties extends { kind: infer K, } ? K : never; type ErrorMessages = { readonly [K in ErrorKinds]: string }; @@ -106,7 +106,7 @@ const errorMessages: ErrorMessages = { "Can't have non-specified required properties but forbidden additionalTypes at ${ref}", SchemaNoTypeSpecified: "JSON Schema must specify at least one type at ${ref}", SchemaInvalidType: "Invalid type ${type} in JSON Schema at ${ref}", - SchemaFalseNotSupported: 'Schema "false" is not supported at ${ref}', + SchemaFalseNotSupported: "Schema \"false\" is not supported at ${ref}", SchemaInvalidJSONSchemaType: "Value of type ${type} is not valid JSON Schema at ${ref}", SchemaRequiredMustBeStringOrStringArray: "`required` must be string or array of strings, but is ${actual} at ${ref}", @@ -161,25 +161,25 @@ const errorMessages: ErrorMessages = { RendererUnknownOptionValue: "Unknown value ${value} for option ${name}", // TypeScript input - TypeScriptCompilerError: "TypeScript error: ${message}" + TypeScriptCompilerError: "TypeScript error: ${message}", }; -export type ErrorPropertiesForName = Extract extends { properties: infer P } +export type ErrorPropertiesForName = Extract extends { properties: infer P, } ? P : never; export class QuickTypeError extends Error { - constructor( + constructor ( readonly errorMessage: string, readonly messageName: string, userMessage: string, - readonly properties: StringMap + readonly properties: StringMap, ) { super(userMessage); } } -export function messageError(kind: N, properties: ErrorPropertiesForName): never { +export function messageError (kind: N, properties: ErrorPropertiesForName): never { const message = errorMessages[kind]; let userMessage: string = message; const propertiesMap = properties as StringMap; @@ -193,16 +193,17 @@ export function messageError(kind: N, properties: ErrorPro } else if (typeof value !== "string") { value = JSON.stringify(value); } + userMessage = userMessage.replace("${" + name + "}", value); } throw new QuickTypeError(message, kind, userMessage, propertiesMap); } -export function messageAssert( +export function messageAssert ( assertion: boolean, kind: N, - properties: ErrorPropertiesForName + properties: ErrorPropertiesForName, ): void { if (assertion) return; return messageError(kind, properties); diff --git a/packages/quicktype-core/src/Naming.ts b/packages/quicktype-core/src/Naming.ts index a8508ca51..819163748 100644 --- a/packages/quicktype-core/src/Naming.ts +++ b/packages/quicktype-core/src/Naming.ts @@ -10,22 +10,25 @@ import { setFilterMap, iterableFirst, iterableEvery, - mapMergeInto + mapMergeInto, } from "collection-utils"; import { defined, assert, panic } from "./support/Support"; export class Namespace { readonly forbiddenNamespaces: ReadonlySet; + readonly additionalForbidden: ReadonlySet; + private readonly _children = new Set(); + private readonly _members = new Set(); - constructor( + constructor ( _name: string, parent: Namespace | undefined, forbiddenNamespaces: Iterable, - additionalForbidden: Iterable + additionalForbidden: Iterable, ) { this.forbiddenNamespaces = new Set(forbiddenNamespaces); this.additionalForbidden = new Set(additionalForbidden); @@ -34,19 +37,19 @@ export class Namespace { } } - private addChild(child: Namespace): void { + private addChild (child: Namespace): void { this._children.add(child); } - get children(): ReadonlySet { + get children (): ReadonlySet { return this._children; } - get members(): ReadonlySet { + get members (): ReadonlySet { return this._members; } - get forbiddenNameds(): ReadonlySet { + get forbiddenNameds (): ReadonlySet { // FIXME: cache return setUnion(this.additionalForbidden, ...Array.from(this.forbiddenNamespaces).map(ns => ns.members)); } @@ -77,16 +80,16 @@ export type NameStyle = (rawName: string) => string; export class Namer { private readonly _prefixes: ReadonlySet; - constructor(readonly name: string, readonly nameStyle: NameStyle, prefixes: string[]) { + constructor (readonly name: string, readonly nameStyle: NameStyle, prefixes: string[]) { this._prefixes = new Set(prefixes); } // The namesIterable comes directly out of the context and will // be modified if we assign - assignNames( + assignNames ( names: ReadonlyMap, forbiddenNamesIterable: Iterable, - namesToAssignIterable: Iterable + namesToAssignIterable: Iterable, ): ReadonlyMap { const forbiddenNames = new Set(forbiddenNamesIterable); const namesToAssign = Array.from(namesToAssignIterable); @@ -105,7 +108,7 @@ export class Namer { proposedNames, proposed => !forbiddenNames.has(namingFunction.nameStyle(proposed)) && - namesToAssign.every(n => n === name || !n.proposeUnstyledNames(names).has(proposed)) + namesToAssign.every(n => n === name || !n.proposeUnstyledNames(names).has(proposed)), ); if (maybeUniqueName !== undefined) { const styledName = namingFunction.nameStyle(maybeUniqueName); @@ -135,6 +138,7 @@ export class Namer { nameToTry = `${originalName}_${suffixNumber.toString()}`; suffixNumber++; } + const styledName = name.namingFunction.nameStyle(nameToTry); const assigned = name.nameAssignments(forbiddenNames, styledName); if (assigned === null) continue; @@ -161,10 +165,10 @@ const funPrefixes = [ "Magenta", "Frisky", "Mischievous", - "Braggadocious" + "Braggadocious", ]; -export function funPrefixNamer(name: string, nameStyle: NameStyle): Namer { +export function funPrefixNamer (name: string, nameStyle: NameStyle): Namer { return new Namer(name, nameStyle, funPrefixes); } @@ -177,30 +181,30 @@ export abstract class Name { private readonly _associates = new Set(); // If a Named is fixed, the namingFunction is undefined. - constructor(private readonly _namingFunction: Namer | undefined, readonly order: number) {} + constructor (private readonly _namingFunction: Namer | undefined, readonly order: number) {} - addAssociate(associate: AssociatedName): void { + addAssociate (associate: AssociatedName): void { this._associates.add(associate); } - abstract get dependencies(): ReadonlyArray; + abstract get dependencies (): readonly Name[]; - isFixed(): this is FixedName { + isFixed (): this is FixedName { return this instanceof FixedName; } - get namingFunction(): Namer { + get namingFunction (): Namer { return defined(this._namingFunction); } // Must return at least one proposal. The proposals are considered in order. - abstract proposeUnstyledNames(names: ReadonlyMap): ReadonlySet; + abstract proposeUnstyledNames (names: ReadonlyMap): ReadonlySet; - firstProposedName(names: ReadonlyMap): string { + firstProposedName (names: ReadonlyMap): string { return defined(iterableFirst(this.proposeUnstyledNames(names))); } - nameAssignments(forbiddenNames: ReadonlySet, assignedName: string): ReadonlyMap | null { + nameAssignments (forbiddenNames: ReadonlySet, assignedName: string): ReadonlyMap | null { if (forbiddenNames.has(assignedName)) return null; const assignments = new Map([[this, assignedName]]); for (const an of this._associates) { @@ -208,31 +212,33 @@ export abstract class Name { if (forbiddenNames.has(associatedAssignedName)) { return null; } + assignments.set(an, associatedAssignedName); } + return assignments; } } // FIXME: FixedNameds should optionally be user-configurable export class FixedName extends Name { - constructor(private readonly _fixedName: string) { + constructor (private readonly _fixedName: string) { super(undefined, 0); } - get dependencies(): ReadonlyArray { + get dependencies (): readonly Name[] { return []; } - addAssociate(_: AssociatedName): never { + addAssociate (_: AssociatedName): never { return panic("Cannot add associates to fixed names"); } - get fixedName(): string { + get fixedName (): string { return this._fixedName; } - proposeUnstyledNames(_?: ReadonlyMap): ReadonlySet { + proposeUnstyledNames (_?: ReadonlyMap): ReadonlySet { return panic("Only fixedName should be called on FixedName."); } } @@ -240,30 +246,30 @@ export class FixedName extends Name { export class SimpleName extends Name { private readonly _unstyledNames: ReadonlySet; - constructor(unstyledNames: Iterable, namingFunction: Namer, order: number) { + constructor (unstyledNames: Iterable, namingFunction: Namer, order: number) { super(namingFunction, order); this._unstyledNames = new Set(unstyledNames); } - get dependencies(): ReadonlyArray { + get dependencies (): readonly Name[] { return []; } - proposeUnstyledNames(_?: ReadonlyMap): ReadonlySet { + proposeUnstyledNames (_?: ReadonlyMap): ReadonlySet { return this._unstyledNames; } } export class AssociatedName extends Name { - constructor(private readonly _sponsor: Name, order: number, readonly getName: (sponsorName: string) => string) { + constructor (private readonly _sponsor: Name, order: number, readonly getName: (sponsorName: string) => string) { super(undefined, order); } - get dependencies(): ReadonlyArray { + get dependencies (): readonly Name[] { return [this._sponsor]; } - proposeUnstyledNames(_?: ReadonlyMap): never { + proposeUnstyledNames (_?: ReadonlyMap): never { return panic("AssociatedName must be assigned via its sponsor"); } } @@ -271,10 +277,10 @@ export class AssociatedName extends Name { export class DependencyName extends Name { private readonly _dependencies: ReadonlySet; - constructor( + constructor ( namingFunction: Namer | undefined, order: number, - private readonly _proposeUnstyledName: (lookup: (n: Name) => string) => string + private readonly _proposeUnstyledName: (lookup: (n: Name) => string) => string, ) { super(namingFunction, order); const dependencies: Name[] = []; @@ -285,42 +291,45 @@ export class DependencyName extends Name { this._dependencies = new Set(dependencies); } - get dependencies(): ReadonlyArray { + get dependencies (): readonly Name[] { return Array.from(this._dependencies); } - proposeUnstyledNames(names: ReadonlyMap): ReadonlySet { + proposeUnstyledNames (names: ReadonlyMap): ReadonlySet { return new Set([ this._proposeUnstyledName(n => { assert(this._dependencies.has(n), "DependencyName proposer is not pure"); return defined(names.get(n)); - }) + }), ]); } } -export function keywordNamespace(name: string, keywords: string[]) { +export function keywordNamespace (name: string, keywords: string[]) { const ns = new Namespace(name, undefined, [], []); for (const kw of keywords) { ns.add(new FixedName(kw)); } + return ns; } -function allNamespacesRecursively(namespaces: Iterable): ReadonlySet { +function allNamespacesRecursively (namespaces: Iterable): ReadonlySet { return setUnion(namespaces, ...Array.from(setMap(namespaces, ns => allNamespacesRecursively(ns.children)))); } class NamingContext { private readonly _names: Map = new Map(); + private readonly _namedsForName: Map> = new Map(); + readonly namespaces: ReadonlySet; - constructor(rootNamespaces: Iterable) { + constructor (rootNamespaces: Iterable) { this.namespaces = allNamespacesRecursively(rootNamespaces); } - get names(): ReadonlyMap { + get names (): ReadonlyMap { return this._names; } @@ -329,7 +338,7 @@ class NamingContext { return named.dependencies.every((n: Name) => this._names.has(n)); }; - areForbiddensFullyNamed(namespace: Namespace): boolean { + areForbiddensFullyNamed (namespace: Namespace): boolean { return iterableEvery(namespace.forbiddenNameds, n => this._names.has(n)); } @@ -343,6 +352,7 @@ class NamingContext { return true; } } + return false; }; @@ -355,12 +365,13 @@ class NamingContext { namedsForName = new Set(); this._namedsForName.set(name, namedsForName); } + namedsForName.add(named); }; } // Naming algorithm -export function assignNames(rootNamespaces: Iterable): ReadonlyMap { +export function assignNames (rootNamespaces: Iterable): ReadonlyMap { const ctx = new NamingContext(rootNamespaces); // Assign all fixed names. @@ -404,7 +415,7 @@ export function assignNames(rootNamespaces: Iterable): ReadonlyMap n.namingFunction); for (const [namer, namedsForNamingFunction] of byNamingFunction) { const byProposed = setGroupBy(namedsForNamingFunction, n => - n.namingFunction.nameStyle(n.firstProposedName(ctx.names)) + n.namingFunction.nameStyle(n.firstProposedName(ctx.names)), ); for (const [, nameds] of byProposed) { // 3. Use each set's naming function to name its members. @@ -413,6 +424,7 @@ export function assignNames(rootNamespaces: Iterable): ReadonlyMap; +export interface RenderResult { names: ReadonlyMap; -}; + sources: ReadonlyMap; +} export type BlankLinePosition = "none" | "interposing" | "leading" | "leading-and-interposing"; export type BlankLineConfig = BlankLinePosition | [BlankLinePosition, number]; -function getBlankLineConfig(cfg: BlankLineConfig): { position: BlankLinePosition; count: number } { +function getBlankLineConfig (cfg: BlankLineConfig): { count: number, position: BlankLinePosition, } { if (Array.isArray(cfg)) { return { position: cfg[0], count: cfg[1] }; } + return { position: cfg, count: 1 }; } -function lineIndentation(line: string): { indent: number; text: string | null } { +function lineIndentation (line: string): { indent: number, text: string | null, } { const len = line.length; let indent = 0; for (let i = 0; i < len; i++) { @@ -36,102 +40,112 @@ function lineIndentation(line: string): { indent: number; text: string | null } return { indent, text: line.substring(i) }; } } + return { indent: 0, text: null }; } -export type RenderContext = { - typeGraph: TypeGraph; +export interface RenderContext { leadingComments?: Comment[]; -}; + typeGraph: TypeGraph; +} export type ForEachPosition = "first" | "last" | "middle" | "only"; class EmitContext { private _lastNewline?: NewlineSource; - // @ts-ignore: Initialized in startEmit, which is called from the constructor - private _emitted: Sourcelike[]; - // @ts-ignore: Initialized in startEmit, which is called from the constructor - private _currentEmitTarget: Sourcelike[]; - // @ts-ignore: Initialized in startEmit, which is called from the constructor + + // @ts-expect-error: Initialized in startEmit, which is called from the constructor + private readonly _emitted: Sourcelike[]; + + // @ts-expect-error: Initialized in startEmit, which is called from the constructor + private readonly _currentEmitTarget: Sourcelike[]; + + // @ts-expect-error: Initialized in startEmit, which is called from the constructor private _numBlankLinesNeeded: number; - // @ts-ignore: Initialized in startEmit, which is called from the constructor + + // @ts-expect-error: Initialized in startEmit, which is called from the constructor private _preventBlankLine: boolean; - constructor() { + constructor () { this._currentEmitTarget = this._emitted = []; this._numBlankLinesNeeded = 0; this._preventBlankLine = true; // no blank lines at start of file } - get isEmpty(): boolean { + get isEmpty (): boolean { return this._emitted.length === 0; } - get isNested(): boolean { + get isNested (): boolean { return this._emitted !== this._currentEmitTarget; } - get source(): Sourcelike[] { + get source (): Sourcelike[] { return this._emitted; } - private pushItem(item: Sourcelike): void { + private pushItem (item: Sourcelike): void { this._currentEmitTarget.push(item); this._preventBlankLine = false; } - emitNewline(): void { + emitNewline (): void { const nl = newline(); this.pushItem(nl); this._lastNewline = nl; } - emitItem(item: Sourcelike): void { + emitItem (item: Sourcelike): void { if (!this.isEmpty) { for (let i = 0; i < this._numBlankLinesNeeded; i++) { this.emitNewline(); } } + this._numBlankLinesNeeded = 0; this.pushItem(item); } - containsItem(item: Sourcelike): boolean { + containsItem (item: Sourcelike): boolean { const existingItem = this._currentEmitTarget.find((value: Sourcelike) => item === value); return existingItem !== undefined; } - ensureBlankLine(numBlankLines: number): void { + ensureBlankLine (numBlankLines: number): void { if (this._preventBlankLine) return; this._numBlankLinesNeeded = Math.max(this._numBlankLinesNeeded, numBlankLines); } - preventBlankLine(): void { + preventBlankLine (): void { this._numBlankLinesNeeded = 0; this._preventBlankLine = true; } - changeIndent(offset: number): void { + changeIndent (offset: number): void { if (this._lastNewline === undefined) { return panic("Cannot change indent for the first line"); } + this._lastNewline.indentationChange += offset; } } export abstract class Renderer { protected readonly typeGraph: TypeGraph; + protected readonly leadingComments: Comment[] | undefined; private _names: ReadonlyMap | undefined; - private _finishedFiles: Map; - private _finishedEmitContexts: Map; + + private readonly _finishedFiles: Map; + + private readonly _finishedEmitContexts: Map; private _emitContext: EmitContext; - constructor( + constructor ( protected readonly targetLanguage: TargetLanguage, - renderContext: RenderContext + renderContext: RenderContext, ) { this.typeGraph = renderContext.typeGraph; this.leadingComments = renderContext.leadingComments; @@ -141,19 +155,19 @@ export abstract class Renderer { this._emitContext = new EmitContext(); } - ensureBlankLine(numBlankLines = 1): void { + ensureBlankLine (numBlankLines = 1): void { this._emitContext.ensureBlankLine(numBlankLines); } - preventBlankLine(): void { + preventBlankLine (): void { this._emitContext.preventBlankLine(); } - emitItem(item: Sourcelike): void { + emitItem (item: Sourcelike): void { this._emitContext.emitItem(item); } - emitItemOnce(item: Sourcelike): boolean { + emitItemOnce (item: Sourcelike): boolean { if (this._emitContext.containsItem(item)) { return false; } @@ -162,7 +176,7 @@ export abstract class Renderer { return true; } - emitLineOnce(...lineParts: Sourcelike[]): void { + emitLineOnce (...lineParts: Sourcelike[]): void { let lineEmitted = true; if (lineParts.length === 1) { lineEmitted = this.emitItemOnce(lineParts[0]); @@ -175,16 +189,17 @@ export abstract class Renderer { } } - emitLine(...lineParts: Sourcelike[]): void { + emitLine (...lineParts: Sourcelike[]): void { if (lineParts.length === 1) { this._emitContext.emitItem(lineParts[0]); } else if (lineParts.length > 1) { this._emitContext.emitItem(lineParts); } + this._emitContext.emitNewline(); } - emitMultiline(linesString: string): void { + emitMultiline (linesString: string): void { const lines = linesString.split("\n"); const numLines = lines.length; if (numLines === 0) return; @@ -203,12 +218,13 @@ export abstract class Renderer { this._emitContext.emitNewline(); } } + if (currentIndent !== 0) { this.changeIndent(-currentIndent); } } - gatherSource(emitter: () => void): Sourcelike[] { + gatherSource (emitter: () => void): Sourcelike[] { const oldEmitContext = this._emitContext; this._emitContext = new EmitContext(); emitter(); @@ -218,19 +234,19 @@ export abstract class Renderer { return source; } - emitGatheredSource(items: Sourcelike[]): void { + emitGatheredSource (items: Sourcelike[]): void { for (const item of items) { this._emitContext.emitItem(item); } } - emitAnnotated(annotation: AnnotationData, emitter: () => void): void { + emitAnnotated (annotation: AnnotationData, emitter: () => void): void { const lines = this.gatherSource(emitter); const source = sourcelikeToSource(lines); this._emitContext.emitItem(annotated(annotation, source)); } - emitIssue(message: string, emitter: () => void): void { + emitIssue (message: string, emitter: () => void): void { this.emitAnnotated(new IssueAnnotationData(message), emitter); } @@ -241,7 +257,7 @@ export abstract class Renderer { this._emitContext.emitNewline(); }; - changeIndent(offset: number): void { + changeIndent (offset: number): void { this._emitContext.changeIndent(offset); } @@ -260,7 +276,7 @@ export abstract class Renderer { iterable: Iterable<[K, V]>, interposedBlankLines: number, leadingBlankLines: number, - emitter: (v: V, k: K, position: ForEachPosition) => void + emitter: (v: V, k: K, position: ForEachPosition) => void, ): boolean { let didEmit = false; this.iterableForEach(iterable, ([k, v], position) => { @@ -269,6 +285,7 @@ export abstract class Renderer { } else { this.ensureBlankLine(interposedBlankLines); } + emitter(v, k, position); didEmit = true; }); @@ -278,28 +295,28 @@ export abstract class Renderer { forEachWithBlankLines( iterable: Iterable<[K, V]>, blankLineConfig: BlankLineConfig, - emitter: (v: V, k: K, position: ForEachPosition) => void + emitter: (v: V, k: K, position: ForEachPosition) => void, ): boolean { const { position, count } = getBlankLineConfig(blankLineConfig); - const interposing = ["interposing", "leading-and-interposing"].indexOf(position) >= 0; - const leading = ["leading", "leading-and-interposing"].indexOf(position) >= 0; + const interposing = ["interposing", "leading-and-interposing"].includes(position); + const leading = ["leading", "leading-and-interposing"].includes(position); return this.forEach(iterable, interposing ? count : 0, leading ? count : 0, emitter); } - indent(fn: () => void): void { + indent (fn: () => void): void { this.changeIndent(1); fn(); this.changeIndent(-1); } - protected abstract setUpNaming(): Iterable; - protected abstract emitSource(givenOutputFilename: string): void; + protected abstract setUpNaming (): Iterable; + protected abstract emitSource (givenOutputFilename: string): void; - private assignNames(): ReadonlyMap { + private assignNames (): ReadonlyMap { return assignNames(this.setUpNaming()); } - protected initializeEmitContextForFilename(filename: string): void { + protected initializeEmitContextForFilename (filename: string): void { if (this._finishedEmitContexts.has(filename.toLowerCase())) { const existingEmitContext = this._finishedEmitContexts.get(filename.toLowerCase()); if (existingEmitContext !== undefined) { @@ -308,10 +325,10 @@ export abstract class Renderer { } } - protected finishFile(filename: string): void { + protected finishFile (filename: string): void { if (this._finishedFiles.has(filename)) { console.log( - `[WARNING] Tried to emit file ${filename} more than once. If performing multi-file output this warning can be safely ignored.` + `[WARNING] Tried to emit file ${filename} more than once. If performing multi-file output this warning can be safely ignored.`, ); } @@ -323,19 +340,21 @@ export abstract class Renderer { this._emitContext = new EmitContext(); } - render(givenOutputFilename: string): RenderResult { + render (givenOutputFilename: string): RenderResult { this._names = this.assignNames(); this.emitSource(givenOutputFilename); if (!this._emitContext.isEmpty) { this.finishFile(givenOutputFilename); } + return { sources: this._finishedFiles, names: this._names }; } - get names(): ReadonlyMap { + get names (): ReadonlyMap { if (this._names === undefined) { return panic("Names accessed before they were assigned"); } + return this._names; } } diff --git a/packages/quicktype-core/src/RendererOptions.ts b/packages/quicktype-core/src/RendererOptions.ts index 9ef964b42..f3fae9ffa 100644 --- a/packages/quicktype-core/src/RendererOptions.ts +++ b/packages/quicktype-core/src/RendererOptions.ts @@ -9,17 +9,17 @@ import { hasOwnProperty } from "collection-utils"; export type OptionKind = "primary" | "secondary"; export interface OptionDefinition { - name: string; - type: StringConstructor | BooleanConstructor; - kind?: OptionKind; - renderer?: boolean; alias?: string; - multiple?: boolean; defaultOption?: boolean; defaultValue?: any; - typeLabel?: string; description: string; + kind?: OptionKind; legalValues?: string[]; + multiple?: boolean; + name: string; + renderer?: boolean; + type: StringConstructor | BooleanConstructor; + typeLabel?: string; } /** @@ -29,21 +29,22 @@ export interface OptionDefinition { export abstract class Option { readonly definition: OptionDefinition; - constructor(definition: OptionDefinition) { + constructor (definition: OptionDefinition) { definition.renderer = true; this.definition = definition; assert(definition.kind !== undefined, "Renderer option kind must be defined"); } - getValue(values: { [name: string]: any }): T { + getValue (values: { [name: string]: any, }): T { const value = values[this.definition.name]; if (value === undefined) { return this.definition.defaultValue; } + return value; } - get cliDefinitions(): { display: OptionDefinition[]; actual: OptionDefinition[] } { + get cliDefinitions (): { actual: OptionDefinition[], display: OptionDefinition[], } { return { actual: [this.definition], display: [this.definition] }; } } @@ -51,14 +52,15 @@ export abstract class Option { export type OptionValueType = O extends Option ? T : never; export type OptionValues = { [P in keyof T]: OptionValueType }; -export function getOptionValues }>( +export function getOptionValues, }> ( options: T, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): OptionValues { - const optionValues: { [name: string]: any } = {}; + const optionValues: { [name: string]: any, } = {}; for (const name of Object.getOwnPropertyNames(options)) { optionValues[name] = options[name].getValue(untypedOptionValues); } + return optionValues as OptionValues; } @@ -72,32 +74,32 @@ export class BooleanOption extends Option { * @param defaultValue The default value. * @param kind Whether it's a primary or secondary option. */ - constructor(name: string, description: string, defaultValue: boolean, kind: OptionKind = "primary") { + constructor (name: string, description: string, defaultValue: boolean, kind: OptionKind = "primary") { super({ name, kind, type: Boolean, description, - defaultValue + defaultValue, }); } - get cliDefinitions(): { display: OptionDefinition[]; actual: OptionDefinition[] } { + get cliDefinitions (): { actual: OptionDefinition[], display: OptionDefinition[], } { const negated = Object.assign({}, this.definition, { name: `no-${this.definition.name}`, - defaultValue: !this.definition.defaultValue + defaultValue: !this.definition.defaultValue, }); const display = Object.assign({}, this.definition, { name: `[no-]${this.definition.name}`, - description: `${this.definition.description} (${this.definition.defaultValue ? "on" : "off"} by default)` + description: `${this.definition.description} (${this.definition.defaultValue ? "on" : "off"} by default)`, }); return { display: [display], - actual: [this.definition, negated] + actual: [this.definition, negated], }; } - getValue(values: { [name: string]: any }): boolean { + getValue (values: { [name: string]: any, }): boolean { let value = values[this.definition.name]; if (value === undefined) { value = this.definition.defaultValue; @@ -123,12 +125,12 @@ export class BooleanOption extends Option { } export class StringOption extends Option { - constructor( + constructor ( name: string, description: string, typeLabel: string, defaultValue: string, - kind: OptionKind = "primary" + kind: OptionKind = "primary", ) { const definition = { name, @@ -136,25 +138,26 @@ export class StringOption extends Option { type: String, description, typeLabel, - defaultValue + defaultValue, }; super(definition); } } export class EnumOption extends Option { - private readonly _values: { [name: string]: T }; + private readonly _values: { [name: string]: T, }; - constructor( + constructor ( name: string, description: string, - values: [string, T][], + values: Array<[string, T]>, defaultValue: string | undefined = undefined, - kind: OptionKind = "primary" + kind: OptionKind = "primary", ) { if (defaultValue === undefined) { defaultValue = values[0][0]; } + const definition = { name, kind, @@ -162,7 +165,7 @@ export class EnumOption extends Option { description, typeLabel: values.map(([n, _]) => n).join("|"), legalValues: values.map(([n, _]) => n), - defaultValue + defaultValue, }; super(definition); @@ -172,14 +175,16 @@ export class EnumOption extends Option { } } - getValue(values: { [name: string]: any }): T { + getValue (values: { [name: string]: any, }): T { let name: string = values[this.definition.name]; if (name === undefined) { name = this.definition.defaultValue; } + if (!hasOwnProperty(this._values, name)) { return messageError("RendererUnknownOptionValue", { value: name, name: this.definition.name }); } + return this._values[name]; } } diff --git a/packages/quicktype-core/src/Run.ts b/packages/quicktype-core/src/Run.ts index 195417cb9..1faaed8e6 100644 --- a/packages/quicktype-core/src/Run.ts +++ b/packages/quicktype-core/src/Run.ts @@ -1,13 +1,15 @@ import { mapFirst } from "collection-utils"; import * as targetLanguages from "./language/All"; -import { TargetLanguage, MultiFileRenderResult } from "./TargetLanguage"; -import { SerializedRenderResult, Annotation, Location, Span } from "./Source"; +import { type TargetLanguage, type MultiFileRenderResult } from "./TargetLanguage"; +import { type SerializedRenderResult, type Annotation, type Location, type Span } from "./Source"; import { assert } from "./support/Support"; import { combineClasses } from "./rewrites/CombineClasses"; import { inferMaps } from "./rewrites/InferMaps"; -import { TypeBuilder, StringTypeMapping } from "./TypeBuilder"; -import { TypeGraph, noneToAny, optionalToNullable, removeIndirectionIntersections } from "./TypeGraph"; +import { type StringTypeMapping } from "./TypeBuilder"; +import { TypeBuilder } from "./TypeBuilder"; +import { type TypeGraph} from "./TypeGraph"; +import { noneToAny, optionalToNullable, removeIndirectionIntersections } from "./TypeGraph"; import { initTypeNames } from "./attributes/TypeNames"; import { gatherNames } from "./GatherNames"; import { expandStrings } from "./rewrites/ExpandStrings"; @@ -18,26 +20,30 @@ import { messageError } from "./Messages"; import { InputData } from "./input/Inputs"; import { flattenStrings } from "./rewrites/FlattenStrings"; import { makeTransformations } from "./MakeTransformations"; -import { TransformedStringTypeKind } from "./Type"; +import { type TransformedStringTypeKind } from "./Type"; import { type Comment } from "./support/Comments"; -export function getTargetLanguage(nameOrInstance: string | TargetLanguage): TargetLanguage { +export function getTargetLanguage (nameOrInstance: string | TargetLanguage): TargetLanguage { if (typeof nameOrInstance === "object") { return nameOrInstance; } + const language = targetLanguages.languageNamed(nameOrInstance); if (language !== undefined) { return language; } + return messageError("DriverUnknownOutputLanguage", { lang: nameOrInstance }); } -export type RendererOptions = { [name: string]: string | boolean }; +export interface RendererOptions { + [name: string]: string | boolean; +} export interface InferenceFlag { description: string; - negationDescription: string; explanation: string; + negationDescription: string; order: number; stringType?: TransformedStringTypeKind; } @@ -48,14 +54,14 @@ export const inferenceFlagsObject = { description: "Detect maps", negationDescription: "Don't infer maps, always use classes", explanation: "Infer maps when object keys look like map keys.", - order: 1 + order: 1, }, /** Whether to infer enum types from JSON data */ inferEnums: { description: "Detect enums", negationDescription: "Don't infer enums, always use strings", explanation: "If string values occur within a relatively small domain,\ninfer them as enum values.", - order: 2 + order: 2, }, /** Whether to convert UUID strings to UUID objects */ inferUuids: { @@ -63,7 +69,7 @@ export const inferenceFlagsObject = { negationDescription: "Don't convert UUIDs to UUID objects", explanation: "Detect UUIDs like '123e4567-e89b-12d3-a456-426655440000' (partial support).", stringType: "uuid" as TransformedStringTypeKind, - order: 3 + order: 3, }, /** Whether to assume that JSON strings that look like dates are dates */ inferDateTimes: { @@ -71,24 +77,24 @@ export const inferenceFlagsObject = { negationDescription: "Don't infer dates or times", explanation: "Infer dates from strings (partial support).", stringType: "date-time" as TransformedStringTypeKind, - order: 4 + order: 4, }, /** Whether to convert stringified integers to integers */ inferIntegerStrings: { description: "Detect integers in strings", negationDescription: "Don't convert stringified integers to integers", - explanation: 'Automatically convert stringified integers to integers.\nFor example, "1" is converted to 1.', + explanation: "Automatically convert stringified integers to integers.\nFor example, \"1\" is converted to 1.", stringType: "integer-string" as TransformedStringTypeKind, - order: 5 + order: 5, }, /** Whether to convert stringified booleans to boolean values */ inferBooleanStrings: { description: "Detect booleans in strings", negationDescription: "Don't convert stringified booleans to booleans", explanation: - 'Automatically convert stringified booleans to booleans.\nFor example, "true" is converted to true.', + "Automatically convert stringified booleans to booleans.\nFor example, \"true\" is converted to true.", stringType: "bool-string" as TransformedStringTypeKind, - order: 6 + order: 6, }, /** Combine similar classes. This doesn't apply to classes from a schema, only from inference. */ combineClasses: { @@ -96,7 +102,7 @@ export const inferenceFlagsObject = { negationDescription: "Don't combine similar classes", explanation: "Combine classes with significantly overlapping properties,\ntreating contingent properties as nullable.", - order: 7 + order: 7, }, /** Whether to treat $ref as references within JSON */ ignoreJsonRefs: { @@ -104,8 +110,8 @@ export const inferenceFlagsObject = { negationDescription: "Treat $ref as a reference in JSON", explanation: "Like in JSON Schema, allow objects like\n'{ $ref: \"#/foo/bar\" }' to refer\nto another part of the input.", - order: 8 - } + order: 8, + }, }; export type InferenceFlagName = keyof typeof inferenceFlagsObject; export const inferenceFlagNames = Object.getOwnPropertyNames(inferenceFlagsObject) as InferenceFlagName[]; @@ -117,57 +123,57 @@ export type InferenceFlags = { [F in InferenceFlagName]: boolean }; * The options type for the main quicktype entry points, * `quicktypeMultiFile` and `quicktype`. */ -export type NonInferenceOptions = { - /** - * The target language for which to produce code. This can be either an instance of `TargetLanguage`, - * or a string specifying one of the names for quicktype's built-in target languages. For example, - * both `cs` and `csharp` will generate C#. - */ - lang: string | TargetLanguage; - /** The input data from which to produce types */ - inputData: InputData; - /** Put class properties in alphabetical order, instead of in the order found in the JSON */ - alphabetizeProperties: boolean; +export interface NonInferenceOptions { /** Make all class property optional */ allPropertiesOptional: boolean; + /** Put class properties in alphabetical order, instead of in the order found in the JSON */ + alphabetizeProperties: boolean; + /** Check that we're propagating all type attributes (unless we actually can't) */ + checkProvenance: boolean; /** - * Make top-levels classes from JSON fixed. That means even if two top-level classes are exactly - * the same, quicktype will still generate two separate types for them. - */ - fixedTopLevels: boolean; - /** Don't render output. This is mainly useful for benchmarking. */ - noRender: boolean; - /** If given, output these comments at the beginning of the main output file */ - leadingComments?: Comment[]; - /** Options for the target language's renderer */ - rendererOptions: RendererOptions; - /** String to use for one indentation level. If not given, use the target language's default. */ - indentation: string | undefined; - /** Name of the output file. Note that quicktype will not write that file, but you'll get its name - * back as a key in the resulting `Map`. + * Print name gathering debug information to the console. This might help to figure out why + * your types get weird names, but the output is quite arcane. */ - outputFilename: string; + debugPrintGatherNames: boolean; /** Print the type graph to the console at every processing step */ debugPrintGraph: boolean; - /** Check that we're propagating all type attributes (unless we actually can't) */ - checkProvenance: boolean; /** * Print type reconstitution debug information to the console. You'll only ever need this if * you're working deep inside quicktype-core. */ debugPrintReconstitution: boolean; - /** - * Print name gathering debug information to the console. This might help to figure out why - * your types get weird names, but the output is quite arcane. - */ - debugPrintGatherNames: boolean; - /** Print all transformations to the console prior to generating code */ - debugPrintTransformations: boolean; - /** Print the time it took for each pass to run */ - debugPrintTimes: boolean; /** Print schema resolving steps */ debugPrintSchemaResolving: boolean; -}; + /** Print the time it took for each pass to run */ + debugPrintTimes: boolean; + /** Print all transformations to the console prior to generating code */ + debugPrintTransformations: boolean; + /** + * Make top-levels classes from JSON fixed. That means even if two top-level classes are exactly + * the same, quicktype will still generate two separate types for them. + */ + fixedTopLevels: boolean; + /** String to use for one indentation level. If not given, use the target language's default. */ + indentation: string | undefined; + /** The input data from which to produce types */ + inputData: InputData; + /** + * The target language for which to produce code. This can be either an instance of `TargetLanguage`, + * or a string specifying one of the names for quicktype's built-in target languages. For example, + * both `cs` and `csharp` will generate C#. + */ + lang: string | TargetLanguage; + /** If given, output these comments at the beginning of the main output file */ + leadingComments?: Comment[]; + /** Don't render output. This is mainly useful for benchmarking. */ + noRender: boolean; + /** Name of the output file. Note that quicktype will not write that file, but you'll get its name + * back as a key in the resulting `Map`. + */ + outputFilename: string; + /** Options for the target language's renderer */ + rendererOptions: RendererOptions; +} export type Options = NonInferenceOptions & InferenceFlags; @@ -188,31 +194,32 @@ const defaultOptions: NonInferenceOptions = { debugPrintGatherNames: false, debugPrintTransformations: false, debugPrintTimes: false, - debugPrintSchemaResolving: false + debugPrintSchemaResolving: false, }; export interface RunContext { - stringTypeMapping: StringTypeMapping; debugPrintReconstitution: boolean; - debugPrintTransformations: boolean; debugPrintSchemaResolving: boolean; + debugPrintTransformations: boolean; + stringTypeMapping: StringTypeMapping; - timeSync(name: string, f: () => Promise): Promise; - time(name: string, f: () => T): T; + time: (name: string, f: () => T) => T; + timeSync: (name: string, f: () => Promise) => Promise; } interface GraphInputs { - targetLanguage: TargetLanguage; - stringTypeMapping: StringTypeMapping; conflateNumbers: boolean; + stringTypeMapping: StringTypeMapping; + targetLanguage: TargetLanguage; typeBuilder: TypeBuilder; } -function makeDefaultInferenceFlags(): InferenceFlags { +function makeDefaultInferenceFlags (): InferenceFlags { const flags = {} as InferenceFlags; for (const flag of inferenceFlagNames) { flags[flag] = true; } + return flags; } @@ -221,7 +228,7 @@ export const defaultInferenceFlags = makeDefaultInferenceFlags(); class Run implements RunContext { private readonly _options: Options; - constructor(options: Partial) { + constructor (options: Partial) { // We must not overwrite defaults with undefined values, which // we sometimes get. this._options = Object.assign({}, defaultOptions, defaultInferenceFlags); @@ -233,7 +240,7 @@ class Run implements RunContext { } } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const targetLanguage = getTargetLanguage(this._options.lang); const mapping = new Map(targetLanguage.stringTypeMapping); for (const flag of inferenceFlagNames) { @@ -242,18 +249,19 @@ class Run implements RunContext { mapping.set(stringType, "string"); } } + return mapping; } - get debugPrintReconstitution(): boolean { + get debugPrintReconstitution (): boolean { return this._options.debugPrintReconstitution === true; } - get debugPrintTransformations(): boolean { + get debugPrintTransformations (): boolean { return this._options.debugPrintTransformations; } - get debugPrintSchemaResolving(): boolean { + get debugPrintSchemaResolving (): boolean { return this._options.debugPrintSchemaResolving; } @@ -264,6 +272,7 @@ class Run implements RunContext { if (this._options.debugPrintTimes) { console.log(`${name} took ${end - start}ms`); } + return result; } @@ -274,10 +283,11 @@ class Run implements RunContext { if (this._options.debugPrintTimes) { console.log(`${name} took ${end - start}ms`); } + return result; } - private makeGraphInputs(): GraphInputs { + private makeGraphInputs (): GraphInputs { const targetLanguage = getTargetLanguage(this._options.lang); const stringTypeMapping = this.stringTypeMapping; const conflateNumbers = !targetLanguage.supportsUnionsWithBothNumberTypes; @@ -287,13 +297,13 @@ class Run implements RunContext { this._options.alphabetizeProperties, this._options.allPropertiesOptional, this._options.checkProvenance, - false + false, ); return { targetLanguage, stringTypeMapping, conflateNumbers, typeBuilder }; } - private async makeGraph(allInputs: InputData): Promise { + private async makeGraph (allInputs: InputData): Promise { const graphInputs = this.makeGraphInputs(); await this.timeSync( @@ -304,14 +314,14 @@ class Run implements RunContext { graphInputs.typeBuilder, this._options.inferMaps, this._options.inferEnums, - this._options.fixedTopLevels - ) + this._options.fixedTopLevels, + ), ); return this.processGraph(allInputs, graphInputs); } - private makeGraphSync(allInputs: InputData): TypeGraph { + private makeGraphSync (allInputs: InputData): TypeGraph { const graphInputs = this.makeGraphInputs(); this.time("read input", () => @@ -320,14 +330,14 @@ class Run implements RunContext { graphInputs.typeBuilder, this._options.inferMaps, this._options.inferEnums, - this._options.fixedTopLevels - ) + this._options.fixedTopLevels, + ), ); return this.processGraph(allInputs, graphInputs); } - private processGraph(allInputs: InputData, graphInputs: GraphInputs): TypeGraph { + private processGraph (allInputs: InputData, graphInputs: GraphInputs): TypeGraph { const { targetLanguage, stringTypeMapping, conflateNumbers, typeBuilder } = graphInputs; let graph = typeBuilder.finish(); @@ -341,7 +351,7 @@ class Run implements RunContext { if (typeBuilder.didAddForwardingIntersection || !this._options.ignoreJsonRefs) { this.time( "remove indirection intersections", - () => (graph = removeIndirectionIntersections(graph, stringTypeMapping, debugPrintReconstitution)) + () => graph = removeIndirectionIntersections(graph, stringTypeMapping, debugPrintReconstitution), ); } @@ -354,24 +364,25 @@ class Run implements RunContext { this.time( "resolve intersections", () => - ([graph, intersectionsDone] = resolveIntersections( + [graph, intersectionsDone] = resolveIntersections( graph, stringTypeMapping, - debugPrintReconstitution - )) + debugPrintReconstitution, + ), ); } + if (!unionsDone) { this.time( "flatten unions", () => - ([graph, unionsDone] = flattenUnions( + [graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, true, - debugPrintReconstitution - )) + debugPrintReconstitution, + ), ); } @@ -384,31 +395,31 @@ class Run implements RunContext { this.time( "replace object type", () => - (graph = replaceObjectType( + graph = replaceObjectType( graph, stringTypeMapping, conflateNumbers, targetLanguage.supportsFullObjectType, - debugPrintReconstitution - )) + debugPrintReconstitution, + ), ); do { this.time( "flatten unions", () => - ([graph, unionsDone] = flattenUnions( + [graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, false, - debugPrintReconstitution - )) + debugPrintReconstitution, + ), ); } while (!unionsDone); if (this._options.combineClasses) { const combinedGraph = this.time("combine classes", () => - combineClasses(this, graph, this._options.alphabetizeProperties, true, false, debugPrintReconstitution) + combineClasses(this, graph, this._options.alphabetizeProperties, true, false, debugPrintReconstitution), ); if (combinedGraph === graph) { graph = combinedGraph; @@ -416,14 +427,14 @@ class Run implements RunContext { this.time( "combine classes cleanup", () => - (graph = combineClasses( + graph = combineClasses( this, combinedGraph, this._options.alphabetizeProperties, false, true, - debugPrintReconstitution - )) + debugPrintReconstitution, + ), ); } } @@ -431,59 +442,60 @@ class Run implements RunContext { if (this._options.inferMaps) { for (;;) { const newGraph = this.time("infer maps", () => - inferMaps(graph, stringTypeMapping, true, debugPrintReconstitution) + inferMaps(graph, stringTypeMapping, true, debugPrintReconstitution), ); if (newGraph === graph) { break; } + graph = newGraph; } } const enumInference = allInputs.needSchemaProcessing ? "all" : this._options.inferEnums ? "infer" : "none"; - this.time("expand strings", () => (graph = expandStrings(this, graph, enumInference))); + this.time("expand strings", () => graph = expandStrings(this, graph, enumInference)); this.time( "flatten unions", () => - ([graph, unionsDone] = flattenUnions( + [graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, false, - debugPrintReconstitution - )) + debugPrintReconstitution, + ), ); assert(unionsDone, "We should only have to flatten unions once after expanding strings"); if (allInputs.needSchemaProcessing) { this.time( "flatten strings", - () => (graph = flattenStrings(graph, stringTypeMapping, debugPrintReconstitution)) + () => graph = flattenStrings(graph, stringTypeMapping, debugPrintReconstitution), ); } - this.time("none to any", () => (graph = noneToAny(graph, stringTypeMapping, debugPrintReconstitution))); + this.time("none to any", () => graph = noneToAny(graph, stringTypeMapping, debugPrintReconstitution)); if (!targetLanguage.supportsOptionalClassProperties) { this.time( "optional to nullable", - () => (graph = optionalToNullable(graph, stringTypeMapping, debugPrintReconstitution)) + () => graph = optionalToNullable(graph, stringTypeMapping, debugPrintReconstitution), ); } - this.time("fixed point", () => (graph = graph.rewriteFixedPoint(false, debugPrintReconstitution))); + this.time("fixed point", () => graph = graph.rewriteFixedPoint(false, debugPrintReconstitution)); - this.time("make transformations", () => (graph = makeTransformations(this, graph, targetLanguage))); + this.time("make transformations", () => graph = makeTransformations(this, graph, targetLanguage)); this.time( "flatten unions", () => - ([graph, unionsDone] = flattenUnions( + [graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, false, - debugPrintReconstitution - )) + debugPrintReconstitution, + ), ); assert(unionsDone, "We should only have to flatten unions once after making transformations"); @@ -496,14 +508,15 @@ class Run implements RunContext { // is different from the one we started out with. this.time( "GC", - () => (graph = graph.garbageCollect(this._options.alphabetizeProperties, debugPrintReconstitution)) + () => graph = graph.garbageCollect(this._options.alphabetizeProperties, debugPrintReconstitution), ); if (this._options.debugPrintGraph) { console.log("\n# gather names"); } + this.time("gather names", () => - gatherNames(graph, !allInputs.needSchemaProcessing, this._options.debugPrintGatherNames) + gatherNames(graph, !allInputs.needSchemaProcessing, this._options.debugPrintGatherNames), ); if (this._options.debugPrintGraph) { graph.printGraph(); @@ -512,20 +525,20 @@ class Run implements RunContext { return graph; } - private makeSimpleTextResult(lines: string[]): MultiFileRenderResult { - return new Map([[this._options.outputFilename, { lines, annotations: [] }]] as [ + private makeSimpleTextResult (lines: string[]): MultiFileRenderResult { + return new Map([[this._options.outputFilename, { lines, annotations: [] }]] as Array<[ string, SerializedRenderResult - ][]); + ]>); } - private preRun(): MultiFileRenderResult | [InputData, TargetLanguage] { + private preRun (): MultiFileRenderResult | [InputData, TargetLanguage] { // FIXME: This makes quicktype not quite reentrant initTypeNames(); const targetLanguage = getTargetLanguage(this._options.lang); const inputData = this._options.inputData; - const needIR = inputData.needIR || targetLanguage.names.indexOf("schema") < 0; + const needIR = inputData.needIR || !targetLanguage.names.includes("schema"); const schemaString = needIR ? undefined : inputData.singleStringSchemaSource(); if (schemaString !== undefined) { @@ -538,7 +551,7 @@ class Run implements RunContext { return [inputData, targetLanguage]; } - async run(): Promise { + async run (): Promise { const preRunResult = this.preRun(); if (!Array.isArray(preRunResult)) { return preRunResult; @@ -551,7 +564,7 @@ class Run implements RunContext { return this.renderGraph(targetLanguage, graph); } - runSync(): MultiFileRenderResult { + runSync (): MultiFileRenderResult { const preRunResult = this.preRun(); if (!Array.isArray(preRunResult)) { return preRunResult; @@ -564,7 +577,7 @@ class Run implements RunContext { return this.renderGraph(targetLanguage, graph); } - private renderGraph(targetLanguage: TargetLanguage, graph: TypeGraph): MultiFileRenderResult { + private renderGraph (targetLanguage: TargetLanguage, graph: TypeGraph): MultiFileRenderResult { if (this._options.noRender) { return this.makeSimpleTextResult(["Done.", ""]); } @@ -575,7 +588,7 @@ class Run implements RunContext { this._options.alphabetizeProperties, this._options.leadingComments, this._options.rendererOptions, - this._options.indentation + this._options.indentation, ); } } @@ -586,19 +599,19 @@ class Run implements RunContext { * @param options Partial options. For options that are not defined, the * defaults will be used. */ -export async function quicktypeMultiFile(options: Partial): Promise { +export async function quicktypeMultiFile (options: Partial): Promise { return await new Run(options).run(); } -export function quicktypeMultiFileSync(options: Partial): MultiFileRenderResult { +export function quicktypeMultiFileSync (options: Partial): MultiFileRenderResult { return new Run(options).runSync(); } -function offsetLocation(loc: Location, lineOffset: number): Location { +function offsetLocation (loc: Location, lineOffset: number): Location { return { line: loc.line + lineOffset, column: loc.column }; } -function offsetSpan(span: Span, lineOffset: number): Span { +function offsetSpan (span: Span, lineOffset: number): Span { return { start: offsetLocation(span.start, lineOffset), end: offsetLocation(span.end, lineOffset) }; } @@ -607,23 +620,26 @@ function offsetSpan(span: Span, lineOffset: number): Span { * are concatenated and prefixed with a `//`-style comment giving the * filename. */ -export function combineRenderResults(result: MultiFileRenderResult): SerializedRenderResult { +export function combineRenderResults (result: MultiFileRenderResult): SerializedRenderResult { if (result.size <= 1) { const first = mapFirst(result); if (first === undefined) { return { lines: [], annotations: [] }; } + return first; } + let lines: string[] = []; let annotations: Annotation[] = []; for (const [filename, srr] of result) { const offset = lines.length + 2; lines = lines.concat([`// ${filename}`, ""], srr.lines); annotations = annotations.concat( - srr.annotations.map(ann => ({ annotation: ann.annotation, span: offsetSpan(ann.span, offset) })) + srr.annotations.map(ann => ({ annotation: ann.annotation, span: offsetSpan(ann.span, offset) })), ); } + return { lines, annotations }; } @@ -635,7 +651,7 @@ export function combineRenderResults(result: MultiFileRenderResult): SerializedR * @param options Partial options. For options that are not defined, the * defaults will be used. */ -export async function quicktype(options: Partial): Promise { +export async function quicktype (options: Partial): Promise { const result = await quicktypeMultiFile(options); return combineRenderResults(result); } diff --git a/packages/quicktype-core/src/Source.ts b/packages/quicktype-core/src/Source.ts index 6898480af..235ac9264 100644 --- a/packages/quicktype-core/src/Source.ts +++ b/packages/quicktype-core/src/Source.ts @@ -1,6 +1,6 @@ import { arrayIntercalate, iterableMax, withDefault } from "collection-utils"; -import { AnnotationData } from "./Annotation"; +import { type AnnotationData } from "./Annotation"; import { Name } from "./Naming"; import { defined, assertNever, panic, assert } from "./support/Support"; import { repeatString } from "./support/Strings"; @@ -20,28 +20,28 @@ export interface TextSource { } export interface NewlineSource { - kind: "newline"; // Number of indentation levels (not spaces!) to change - // the rest of the source by. Positive numbers mean - // indent more, negative mean indent less. The most - // common value will be zero, for no change in - // indentation. +// the rest of the source by. Positive numbers mean +// indent more, negative mean indent less. The most +// common value will be zero, for no change in +// indentation. indentationChange: number; + kind: "newline"; } export interface SequenceSource { kind: "sequence"; - sequence: ReadonlyArray; + sequence: readonly Source[]; } export interface TableSource { kind: "table"; - table: ReadonlyArray>; + table: ReadonlyArray; } export interface AnnotatedSource { - kind: "annotated"; annotation: AnnotationData; + kind: "annotated"; source: Source; } @@ -56,73 +56,78 @@ export interface ModifiedSource { source: Source; } -export function newline(): NewlineSource { +export function newline (): NewlineSource { // We're returning a new object instead of using a singleton // here because `Renderer` will modify `indentationChange`. return { kind: "newline", indentationChange: 0 }; } export type Sourcelike = Source | string | Name | SourcelikeArray; -export interface SourcelikeArray extends Array {} +export type SourcelikeArray = Sourcelike[]; -export function sourcelikeToSource(sl: Sourcelike): Source { +export function sourcelikeToSource (sl: Sourcelike): Source { if (sl instanceof Array) { return { kind: "sequence", - sequence: sl.map(sourcelikeToSource) + sequence: sl.map(sourcelikeToSource), }; } + if (typeof sl === "string") { const lines = sl.split("\n"); if (lines.length === 1) { return { kind: "text", text: sl }; } + return { kind: "sequence", sequence: arrayIntercalate( newline(), - lines.map((l: string) => ({ kind: "text", text: l } as Source)) - ) + lines.map((l: string) => ({ kind: "text", text: l } as Source)), + ), }; } + if (sl instanceof Name) { return { kind: "name", named: sl }; } + return sl; } -export function annotated(annotation: AnnotationData, sl: Sourcelike): Source { +export function annotated (annotation: AnnotationData, sl: Sourcelike): Source { return { kind: "annotated", annotation, - source: sourcelikeToSource(sl) + source: sourcelikeToSource(sl), }; } -export function maybeAnnotated(doAnnotate: boolean, annotation: AnnotationData, sl: Sourcelike): Sourcelike { +export function maybeAnnotated (doAnnotate: boolean, annotation: AnnotationData, sl: Sourcelike): Sourcelike { if (!doAnnotate) { return sl; } + return annotated(annotation, sl); } -export function modifySource(modifier: (serialized: string) => string, sl: Sourcelike): Sourcelike { +export function modifySource (modifier: (serialized: string) => string, sl: Sourcelike): Sourcelike { return { kind: "modified", modifier, - source: sourcelikeToSource(sl) + source: sourcelikeToSource(sl), }; } export interface Location { + column: number; // Both of these are zero-based. line: number; - column: number; } export interface Span { - start: Location; end: Location; + start: Location; } export interface Annotation { @@ -131,11 +136,11 @@ export interface Annotation { } export interface SerializedRenderResult { + annotations: readonly Annotation[]; lines: string[]; - annotations: ReadonlyArray; } -function sourceLineLength(source: Source, names: ReadonlyMap): number { +function sourceLineLength (source: Source, names: ReadonlyMap): number { switch (source.kind) { case "text": return source.text.length; @@ -158,10 +163,10 @@ function sourceLineLength(source: Source, names: ReadonlyMap): num } } -export function serializeRenderResult( +export function serializeRenderResult ( rootSource: Source, names: ReadonlyMap, - indentation: string + indentation: string, ): SerializedRenderResult { let indent = 0; let indentNeeded = 0; @@ -170,28 +175,28 @@ export function serializeRenderResult( let currentLine: string[] = []; const annotations: Annotation[] = []; - function indentIfNeeded(): void { + function indentIfNeeded (): void { if (indentNeeded === 0) return; currentLine.push(repeatString(indentation, indentNeeded)); indentNeeded = 0; } - function flattenCurrentLine(): string { + function flattenCurrentLine (): string { const str = currentLine.join(""); currentLine = [str]; return str; } - function currentLocation(): Location { + function currentLocation (): Location { return { line: lines.length, column: flattenCurrentLine().length }; } - function finishLine(): void { + function finishLine (): void { lines.push(flattenCurrentLine()); currentLine = []; } - function serializeToStringArray(source: Source): void { + function serializeToStringArray (source: Source): void { switch (source.kind) { case "text": indentIfNeeded(); @@ -206,6 +211,7 @@ export function serializeRenderResult( for (const s of source.sequence) { serializeToStringArray(s); } + break; case "table": const t = source.table; @@ -218,6 +224,7 @@ export function serializeRenderResult( for (let i = 0; i < numColumns; i++) { columnWidths.push(defined(iterableMax(widths.map(l => withDefault(l[i], 0))))); } + for (let y = 0; y < numRows; y++) { indentIfNeeded(); const row = defined(t[y]); @@ -231,11 +238,13 @@ export function serializeRenderResult( currentLine.push(repeatString(" ", colWidth - srcWidth)); } } + if (y < numRows - 1) { finishLine(); indentNeeded = indent; } } + break; case "annotated": const start = currentLocation(); @@ -264,31 +273,34 @@ export function serializeRenderResult( return { lines, annotations: annotations }; } -export type MultiWord = { - source: Sourcelike; +export interface MultiWord { needsParens: boolean; -}; + source: Sourcelike; +} -export function singleWord(...source: Sourcelike[]): MultiWord { +export function singleWord (...source: Sourcelike[]): MultiWord { return { source, needsParens: false }; } -export function multiWord(separator: Sourcelike, ...words: Sourcelike[]): MultiWord { +export function multiWord (separator: Sourcelike, ...words: Sourcelike[]): MultiWord { assert(words.length > 0, "Zero words is not multiple"); if (words.length === 1) { return singleWord(words[0]); } + const items: Sourcelike[] = []; for (let i = 0; i < words.length; i++) { if (i > 0) items.push(separator); items.push(words[i]); } + return { source: items, needsParens: true }; } -export function parenIfNeeded({ source, needsParens }: MultiWord): Sourcelike { +export function parenIfNeeded ({ source, needsParens }: MultiWord): Sourcelike { if (needsParens) { return ["(", source, ")"]; } + return source; } diff --git a/packages/quicktype-core/src/TargetLanguage.ts b/packages/quicktype-core/src/TargetLanguage.ts index f1c3a90bf..4d9dbce50 100644 --- a/packages/quicktype-core/src/TargetLanguage.ts +++ b/packages/quicktype-core/src/TargetLanguage.ts @@ -1,92 +1,97 @@ import { mapMap } from "collection-utils"; -import { TypeGraph } from "./TypeGraph"; -import { Renderer, RenderContext } from "./Renderer"; -import { OptionDefinition, Option } from "./RendererOptions"; -import { serializeRenderResult, SerializedRenderResult } from "./Source"; -import { StringTypeMapping } from "./TypeBuilder"; +import { type TypeGraph } from "./TypeGraph"; +import { type Renderer, type RenderContext } from "./Renderer"; +import { type OptionDefinition, type Option } from "./RendererOptions"; +import { type SerializedRenderResult } from "./Source"; +import { serializeRenderResult } from "./Source"; +import { type StringTypeMapping } from "./TypeBuilder"; import { defined } from "./support/Support"; -import { ConvenienceRenderer } from "./ConvenienceRenderer"; -import { Type } from "./Type"; -import { DateTimeRecognizer, DefaultDateTimeRecognizer } from "./DateTime"; +import { type ConvenienceRenderer } from "./ConvenienceRenderer"; +import { type Type } from "./Type"; +import { type DateTimeRecognizer} from "./DateTime"; +import { DefaultDateTimeRecognizer } from "./DateTime"; import { type Comment } from "./support/Comments"; export type MultiFileRenderResult = ReadonlyMap; export abstract class TargetLanguage { - constructor( + constructor ( readonly displayName: string, readonly names: string[], - readonly extension: string + readonly extension: string, ) {} - protected abstract getOptions(): Option[]; + protected abstract getOptions (): Array>; - get optionDefinitions(): OptionDefinition[] { + get optionDefinitions (): OptionDefinition[] { return this.getOptions().map(o => o.definition); } - get cliOptionDefinitions(): { display: OptionDefinition[]; actual: OptionDefinition[] } { + get cliOptionDefinitions (): { actual: OptionDefinition[], display: OptionDefinition[], } { let actual: OptionDefinition[] = []; let display: OptionDefinition[] = []; for (const { cliDefinitions } of this.getOptions()) { actual = actual.concat(cliDefinitions.actual); display = display.concat(cliDefinitions.display); } + return { actual, display }; } - get name(): string { + get name (): string { return defined(this.names[0]); } - protected abstract makeRenderer(renderContext: RenderContext, optionValues: { [name: string]: any }): Renderer; + protected abstract makeRenderer (renderContext: RenderContext, optionValues: { [name: string]: any, }): Renderer; - renderGraphAndSerialize( + renderGraphAndSerialize ( typeGraph: TypeGraph, givenOutputFilename: string, alphabetizeProperties: boolean, leadingComments: Comment[] | undefined, - rendererOptions: { [name: string]: any }, - indentation?: string + rendererOptions: { [name: string]: any, }, + indentation?: string, ): MultiFileRenderResult { if (indentation === undefined) { indentation = this.defaultIndentation; } + const renderContext = { typeGraph, leadingComments }; const renderer = this.makeRenderer(renderContext, rendererOptions); if ((renderer as any).setAlphabetizeProperties !== undefined) { (renderer as ConvenienceRenderer).setAlphabetizeProperties(alphabetizeProperties); } + const renderResult = renderer.render(givenOutputFilename); return mapMap(renderResult.sources, s => serializeRenderResult(s, renderResult.names, defined(indentation))); } - protected get defaultIndentation(): string { + protected get defaultIndentation (): string { return " "; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { return new Map(); } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return false; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return false; } - get supportsFullObjectType(): boolean { + get supportsFullObjectType (): boolean { return false; } - needsTransformerForType(_t: Type): boolean { + needsTransformerForType (_t: Type): boolean { return false; } - get dateTimeRecognizer(): DateTimeRecognizer { + get dateTimeRecognizer (): DateTimeRecognizer { return new DefaultDateTimeRecognizer(); } } diff --git a/packages/quicktype-core/src/Transformers.ts b/packages/quicktype-core/src/Transformers.ts index e64752358..0b978b771 100644 --- a/packages/quicktype-core/src/Transformers.ts +++ b/packages/quicktype-core/src/Transformers.ts @@ -6,143 +6,146 @@ import { addHashCode, definedMapWithDefault, arraySortByInto, - hashString + hashString, } from "collection-utils"; -import { UnionType, Type, EnumType, PrimitiveType, TypeKind } from "./Type"; +import { type Type, type TypeKind } from "./Type"; +import { UnionType, EnumType, PrimitiveType } from "./Type"; import { TypeAttributeKind } from "./attributes/TypeAttributes"; import { panic, assert, indentationString } from "./support/Support"; -import { BaseGraphRewriteBuilder } from "./GraphRewriting"; -import { TypeRef, derefTypeRef, TypeGraph } from "./TypeGraph"; +import { type BaseGraphRewriteBuilder } from "./GraphRewriting"; +import { type TypeRef, type TypeGraph } from "./TypeGraph"; +import { derefTypeRef } from "./TypeGraph"; -function debugStringForType(t: Type): string { +function debugStringForType (t: Type): string { const target = followTargetType(t); if (t === target) { return t.kind; } + return `${t.kind} (${target.kind})`; } -function getNumberOfNodes(xfer: Transformer | undefined): number { +function getNumberOfNodes (xfer: Transformer | undefined): number { return definedMapWithDefault(xfer, 0, x => x.getNumberOfNodes()); } export abstract class Transformer { - constructor(readonly kind: string, protected readonly graph: TypeGraph, readonly sourceTypeRef: TypeRef) {} + constructor (readonly kind: string, protected readonly graph: TypeGraph, readonly sourceTypeRef: TypeRef) {} - get sourceType(): Type { + get sourceType (): Type { return derefTypeRef(this.sourceTypeRef, this.graph); } /** This must return a newly constructed set. */ - getChildren(): Set { + getChildren (): Set { return new Set([this.sourceType]); } - getNumberOfNodes(): number { + getNumberOfNodes (): number { return 1; } - abstract get canFail(): boolean; + abstract get canFail (): boolean; - abstract reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer; + abstract reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer; abstract reconstitute(builder: TBuilder): Transformer; - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof Transformer)) return false; return this.sourceTypeRef === other.sourceTypeRef; } - hashCode(): number { + hashCode (): number { return hashCodeOf(this.sourceTypeRef); } - protected debugDescription(): string { + protected debugDescription (): string { return `${debugStringForType(this.sourceType)} -> ${this.kind}`; } - protected debugPrintContinuations(_indent: number): void { + protected debugPrintContinuations (_indent: number): void { return; } - debugPrint(indent: number): void { + debugPrint (indent: number): void { console.log(indentationString(indent) + this.debugDescription()); this.debugPrintContinuations(indent + 1); } } export abstract class ProducerTransformer extends Transformer { - constructor(kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, readonly consumer: Transformer | undefined) { + constructor (kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, readonly consumer: Transformer | undefined) { super(kind, graph, sourceTypeRef); } - getChildren(): Set { + getChildren (): Set { const children = super.getChildren(); if (this.consumer === undefined) return children; return setUnionInto(children, this.consumer.getChildren()); } - getNumberOfNodes(): number { + getNumberOfNodes (): number { return super.getNumberOfNodes() + getNumberOfNodes(this.consumer); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ProducerTransformer)) return false; return areEqual(this.consumer, other.consumer); } - hashCode(): number { + hashCode (): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.consumer)); } - protected debugPrintContinuations(indent: number): void { + protected debugPrintContinuations (indent: number): void { if (this.consumer === undefined) return; this.consumer.debugPrint(indent); } } export abstract class MatchTransformer extends Transformer { - constructor(kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, readonly transformer: Transformer) { + constructor (kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, readonly transformer: Transformer) { super(kind, graph, sourceTypeRef); } - getChildren(): Set { + getChildren (): Set { return setUnionInto(super.getChildren(), this.transformer.getChildren()); } - getNumberOfNodes(): number { + getNumberOfNodes (): number { return super.getNumberOfNodes() + this.transformer.getNumberOfNodes(); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof MatchTransformer)) return false; return this.transformer.equals(other.transformer); } - hashCode(): number { + hashCode (): number { const h = super.hashCode(); return addHashCode(h, this.transformer.hashCode()); } - protected debugPrintContinuations(indent: number): void { + protected debugPrintContinuations (indent: number): void { this.transformer.debugPrint(indent); } } export class DecodingTransformer extends ProducerTransformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { super("decode", graph, sourceTypeRef, consumer); } - get canFail(): boolean { + get canFail (): boolean { return false; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer !== undefined) { return panic("Reversing a decoding transformer cannot have a continuation"); } @@ -152,7 +155,7 @@ export class DecodingTransformer extends ProducerTransformer { } else { return this.consumer.reverse( targetTypeRef, - new EncodingTransformer(this.graph, this.consumer.sourceTypeRef) + new EncodingTransformer(this.graph, this.consumer.sourceTypeRef), ); } } @@ -161,26 +164,26 @@ export class DecodingTransformer extends ProducerTransformer { return new DecodingTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - definedMap(this.consumer, xfer => xfer.reconstitute(builder)) + definedMap(this.consumer, xfer => xfer.reconstitute(builder)), ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; return other instanceof DecodingTransformer; } } export class EncodingTransformer extends Transformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef) { super("encode", graph, sourceTypeRef); } - get canFail(): boolean { + get canFail (): boolean { return false; } - reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + reverse (_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { return panic("Can't reverse encoding transformer"); } @@ -188,7 +191,7 @@ export class EncodingTransformer extends Transformer { return new EncodingTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof EncodingTransformer)) return false; return true; @@ -196,35 +199,35 @@ export class EncodingTransformer extends Transformer { } export class ArrayDecodingTransformer extends ProducerTransformer { - constructor( + constructor ( graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, private readonly _itemTargetTypeRef: TypeRef, - readonly itemTransformer: Transformer + readonly itemTransformer: Transformer, ) { super("decode-array", graph, sourceTypeRef, consumer); } - getChildren(): Set { + getChildren (): Set { const children = super.getChildren(); children.add(this.itemTargetType); return setUnionInto(children, this.itemTransformer.getChildren()); } - getNumberOfNodes(): number { + getNumberOfNodes (): number { return super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes(); } - get canFail(): boolean { + get canFail (): boolean { return false; } - get itemTargetType(): Type { + get itemTargetType (): Type { return derefTypeRef(this._itemTargetTypeRef, this.graph); } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer !== undefined) { return panic("Reversing a decoding transformer cannot have a continuation"); } @@ -236,7 +239,7 @@ export class ArrayDecodingTransformer extends ProducerTransformer { this.graph, targetTypeRef, this.itemTransformer.sourceTypeRef, - itemTransformer + itemTransformer, ); } else { return this.consumer.reverse( @@ -245,8 +248,8 @@ export class ArrayDecodingTransformer extends ProducerTransformer { this.graph, this.consumer.sourceTypeRef, this.itemTransformer.sourceTypeRef, - itemTransformer - ) + itemTransformer, + ), ); } } @@ -257,59 +260,59 @@ export class ArrayDecodingTransformer extends ProducerTransformer { builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), builder.reconstituteTypeRef(this._itemTargetTypeRef), - this.itemTransformer.reconstitute(builder) + this.itemTransformer.reconstitute(builder), ); } - hashCode(): number { + hashCode (): number { let h = super.hashCode(); h = addHashCode(h, hashCodeOf(this._itemTargetTypeRef)); h = addHashCode(h, this.itemTransformer.hashCode()); return h; } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ArrayDecodingTransformer)) return false; if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) return false; return this.itemTransformer.equals(other.itemTransformer); } - protected debugPrintContinuations(indent: number): void { + protected debugPrintContinuations (indent: number): void { this.itemTransformer.debugPrint(indent); super.debugPrintContinuations(indent); } } export class ArrayEncodingTransformer extends Transformer { - constructor( + constructor ( graph: TypeGraph, sourceTypeRef: TypeRef, private readonly _itemTargetTypeRef: TypeRef, - readonly itemTransformer: Transformer + readonly itemTransformer: Transformer, ) { super("encode-array", graph, sourceTypeRef); } - getChildren(): Set { + getChildren (): Set { const children = super.getChildren(); children.add(this.itemTargetType); return setUnionInto(children, this.itemTransformer.getChildren()); } - getNumberOfNodes(): number { + getNumberOfNodes (): number { return super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes(); } - get canFail(): boolean { + get canFail (): boolean { return false; } - get itemTargetType(): Type { + get itemTargetType (): Type { return derefTypeRef(this._itemTargetTypeRef, this.graph); } - reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + reverse (_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { return panic("Can't reverse array encoding transformer"); } @@ -318,56 +321,58 @@ export class ArrayEncodingTransformer extends Transformer { builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), builder.reconstituteTypeRef(this._itemTargetTypeRef), - this.itemTransformer.reconstitute(builder) + this.itemTransformer.reconstitute(builder), ); } - hashCode(): number { + hashCode (): number { let h = super.hashCode(); h = addHashCode(h, hashCodeOf(this._itemTargetTypeRef)); return addHashCode(h, this.itemTransformer.hashCode()); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ArrayEncodingTransformer)) return false; if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) return false; return this.itemTransformer.equals(other.itemTransformer); } - protected debugPrintContinuations(indent: number): void { + protected debugPrintContinuations (indent: number): void { this.itemTransformer.debugPrint(indent); super.debugPrintContinuations(indent); } } export class ChoiceTransformer extends Transformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef, public readonly transformers: ReadonlyArray) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef, public readonly transformers: readonly Transformer[]) { super("choice", graph, sourceTypeRef); assert(transformers.length > 0, "Choice must have at least one transformer"); } - getChildren(): Set { + getChildren (): Set { let children = super.getChildren(); for (const xfer of this.transformers) { setUnionInto(children, xfer.getChildren()); } + return children; } - getNumberOfNodes(): number { + getNumberOfNodes (): number { let n = 0; for (const xfer of this.transformers) { n += xfer.getNumberOfNodes(); } + return super.getNumberOfNodes() + n; } - get canFail(): boolean { + get canFail (): boolean { return this.transformers.some(xfer => xfer.canFail); } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { const transformers = this.transformers.map(xfer => xfer.reverse(targetTypeRef, continuationTransformer)); if (transformers.every(xfer => xfer instanceof UnionMemberMatchTransformer)) { const memberMatchers = transformers as UnionMemberMatchTransformer[]; @@ -378,10 +383,11 @@ export class ChoiceTransformer extends Transformer { this.graph, targetTypeRef, new ChoiceTransformer(this.graph, subTransformers[0].sourceTypeRef, subTransformers), - first.memberTypeRef + first.memberTypeRef, ); } } + return new ChoiceTransformer(this.graph, targetTypeRef, transformers); } @@ -389,22 +395,22 @@ export class ChoiceTransformer extends Transformer { return new ChoiceTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - this.transformers.map(xfer => xfer.reconstitute(builder)) + this.transformers.map(xfer => xfer.reconstitute(builder)), ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ChoiceTransformer)) return false; return areEqual(this.transformers, other.transformers); } - hashCode(): number { + hashCode (): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.transformers)); } - protected debugPrintContinuations(indent: number): void { + protected debugPrintContinuations (indent: number): void { for (const xfer of this.transformers) { xfer.debugPrint(indent); } @@ -412,7 +418,7 @@ export class ChoiceTransformer extends Transformer { } export class DecodingChoiceTransformer extends Transformer { - constructor( + constructor ( graph: TypeGraph, sourceTypeRef: TypeRef, readonly nullTransformer: Transformer | undefined, @@ -421,14 +427,14 @@ export class DecodingChoiceTransformer extends Transformer { readonly boolTransformer: Transformer | undefined, readonly stringTransformer: Transformer | undefined, readonly arrayTransformer: Transformer | undefined, - readonly objectTransformer: Transformer | undefined + readonly objectTransformer: Transformer | undefined, ) { super("decoding-choice", graph, sourceTypeRef); } - get transformers(): ReadonlyArray { + get transformers (): readonly Transformer[] { const transformers: Transformer[] = []; - function add(xfer: Transformer | undefined) { + function add (xfer: Transformer | undefined) { if (xfer === undefined) return; transformers.push(xfer); } @@ -444,36 +450,38 @@ export class DecodingChoiceTransformer extends Transformer { return transformers; } - getChildren(): Set { + getChildren (): Set { let children = super.getChildren(); for (const xfer of this.transformers) { setUnionInto(children, xfer.getChildren()); } + return children; } - getNumberOfNodes(): number { + getNumberOfNodes (): number { let n = super.getNumberOfNodes(); for (const xfer of this.transformers) { n += getNumberOfNodes(xfer); } + return n; } - get canFail(): boolean { + get canFail (): boolean { return false; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { assert( continuationTransformer === undefined, - "Reversing a decoding transformer can't have a target transformer" + "Reversing a decoding transformer can't have a target transformer", ); let transformers = new Map(); let memberMatchTransformers = new Map(); - function addCase(reversed: Transformer) { + function addCase (reversed: Transformer) { if (reversed instanceof UnionMemberMatchTransformer) { const memberType = reversed.memberType; let arr = memberMatchTransformers.get(memberType); @@ -481,6 +489,7 @@ export class DecodingChoiceTransformer extends Transformer { arr = []; memberMatchTransformers.set(memberType, arr); } + arr.push(reversed); } else { const kind = reversed.sourceType.kind; @@ -489,19 +498,21 @@ export class DecodingChoiceTransformer extends Transformer { arr = []; transformers.set(kind, arr); } + arr.push(reversed); } } - function reverseAndAdd(transformer: Transformer) { + function reverseAndAdd (transformer: Transformer) { const reversed = transformer.reverse(targetTypeRef, undefined); - let cases: ReadonlyArray = []; + let cases: readonly Transformer[] = []; // Flatten nested ChoiceTransformers if (reversed instanceof ChoiceTransformer) { cases = reversed.transformers; } else { cases = [reversed]; } + for (const xfer of cases) { addCase(xfer); } @@ -514,7 +525,7 @@ export class DecodingChoiceTransformer extends Transformer { // If there are non-failing transformers, we ignore the ones that can fail and // just pick the "simplest" non-failing one, being the one with the least number // of nodes. - function filter(xfers: Transformer[]): Transformer[] { + function filter (xfers: Transformer[]): Transformer[] { assert(xfers.length > 0, "Must have at least one transformer"); const nonfailing = xfers.filter(xfer => { @@ -533,7 +544,7 @@ export class DecodingChoiceTransformer extends Transformer { const smallest = arraySortByInto( nonfailing.map(x => [x.getNumberOfNodes(), x] as [number, Transformer]), - ([c, _]) => c + ([c, _]) => c, )[0][1]; return [smallest]; } @@ -552,7 +563,7 @@ export class DecodingChoiceTransformer extends Transformer { } reconstitute(builder: TBuilder): Transformer { - function reconstitute(xf: Transformer | undefined) { + function reconstitute (xf: Transformer | undefined) { if (xf === undefined) return undefined; return xf.reconstitute(builder); } @@ -566,11 +577,11 @@ export class DecodingChoiceTransformer extends Transformer { reconstitute(this.boolTransformer), reconstitute(this.stringTransformer), reconstitute(this.arrayTransformer), - reconstitute(this.objectTransformer) + reconstitute(this.objectTransformer), ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof DecodingChoiceTransformer)) return false; if (!areEqual(this.nullTransformer, other.nullTransformer)) return false; @@ -583,7 +594,7 @@ export class DecodingChoiceTransformer extends Transformer { return true; } - hashCode(): number { + hashCode (): number { let h = super.hashCode(); h = addHashCode(h, hashCodeOf(this.nullTransformer)); h = addHashCode(h, hashCodeOf(this.integerTransformer)); @@ -595,7 +606,7 @@ export class DecodingChoiceTransformer extends Transformer { return h; } - protected debugPrintContinuations(indent: number): void { + protected debugPrintContinuations (indent: number): void { for (const xfer of this.transformers) { xfer.debugPrint(indent); } @@ -603,31 +614,32 @@ export class DecodingChoiceTransformer extends Transformer { } export class UnionMemberMatchTransformer extends MatchTransformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, readonly memberTypeRef: TypeRef) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, readonly memberTypeRef: TypeRef) { super("union-member-match", graph, sourceTypeRef, transformer); } - get sourceType(): UnionType { + get sourceType (): UnionType { const t = derefTypeRef(this.sourceTypeRef, this.graph); if (!(t instanceof UnionType)) { return panic("The source of a union member match transformer must be a union type"); } + return t; } - get canFail(): boolean { + get canFail (): boolean { return true; } - get memberType(): Type { + get memberType (): Type { return derefTypeRef(this.memberTypeRef, this.graph); } - getChildren(): Set { + getChildren (): Set { return super.getChildren().add(this.memberType); } - reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + reverse (_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { return panic("Can't reverse union member match transformer"); } @@ -636,22 +648,22 @@ export class UnionMemberMatchTransformer extends MatchTransformer { builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), this.transformer.reconstitute(builder), - builder.reconstituteTypeRef(this.memberTypeRef) + builder.reconstituteTypeRef(this.memberTypeRef), ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof UnionMemberMatchTransformer)) return false; return this.memberTypeRef === other.memberTypeRef; } - hashCode(): number { + hashCode (): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.memberTypeRef)); } - protected debugDescription(): string { + protected debugDescription (): string { return `${super.debugDescription()} - member: ${debugStringForType(this.memberType)}`; } } @@ -660,31 +672,32 @@ export class UnionMemberMatchTransformer extends MatchTransformer { * This matches strings and enum cases. */ export class StringMatchTransformer extends MatchTransformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, readonly stringCase: string) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, readonly stringCase: string) { super("string-match", graph, sourceTypeRef, transformer); } - get sourceType(): EnumType | PrimitiveType { + get sourceType (): EnumType | PrimitiveType { const t = derefTypeRef(this.sourceTypeRef, this.graph); if (!(t instanceof EnumType) && !(t instanceof PrimitiveType && t.kind === "string")) { return panic("The source of a string match transformer must be an enum or string type"); } + return t; } - get canFail(): boolean { + get canFail (): boolean { return true; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { return this.transformer.reverse( targetTypeRef, new StringProducerTransformer( this.graph, this.transformer.sourceTypeRef, continuationTransformer, - this.stringCase - ) + this.stringCase, + ), ); } @@ -693,36 +706,36 @@ export class StringMatchTransformer extends MatchTransformer { builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), this.transformer.reconstitute(builder), - this.stringCase + this.stringCase, ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof StringMatchTransformer)) return false; return this.stringCase !== other.stringCase; } - hashCode(): number { + hashCode (): number { const h = super.hashCode(); return addHashCode(h, hashString(this.stringCase)); } - protected debugDescription(): string { + protected debugDescription (): string { return `${super.debugDescription()} - case: ${this.stringCase}`; } } export class UnionInstantiationTransformer extends Transformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef) { super("union-instantiation", graph, sourceTypeRef); } - get canFail(): boolean { + get canFail (): boolean { return false; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer === undefined) { return panic("Union instantiation transformer reverse must have a continuation"); } @@ -734,7 +747,7 @@ export class UnionInstantiationTransformer extends Transformer { return new UnionInstantiationTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; return other instanceof UnionInstantiationTransformer; } @@ -744,15 +757,15 @@ export class UnionInstantiationTransformer extends Transformer { * Produces a string or an enum case. */ export class StringProducerTransformer extends ProducerTransformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, readonly result: string) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, readonly result: string) { super("string-producer", graph, sourceTypeRef, consumer); } - get canFail(): boolean { + get canFail (): boolean { return false; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer === undefined) { return panic("Reversing a string producer transformer must have a continuation"); } @@ -766,8 +779,8 @@ export class StringProducerTransformer extends ProducerTransformer { this.graph, this.consumer.sourceTypeRef, continuationTransformer, - this.result - ) + this.result, + ), ); } } @@ -777,42 +790,42 @@ export class StringProducerTransformer extends ProducerTransformer { builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), - this.result + this.result, ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof StringProducerTransformer)) return false; return this.result === other.result; } - hashCode(): number { + hashCode (): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.consumer)); } - protected debugDescription(): string { + protected debugDescription (): string { return `${super.debugDescription()} - result: ${this.result}`; } } export class ParseStringTransformer extends ProducerTransformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { super("parse-string", graph, sourceTypeRef, consumer); } - get canFail(): boolean { + get canFail (): boolean { return true; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new StringifyTransformer(this.graph, targetTypeRef, continuationTransformer); } else { return this.consumer.reverse( targetTypeRef, - new StringifyTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer) + new StringifyTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer), ); } } @@ -821,32 +834,32 @@ export class ParseStringTransformer extends ProducerTransformer { return new ParseStringTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - definedMap(this.consumer, xfer => xfer.reconstitute(builder)) + definedMap(this.consumer, xfer => xfer.reconstitute(builder)), ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; return other instanceof ParseStringTransformer; } } export class StringifyTransformer extends ProducerTransformer { - constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { super("stringify", graph, sourceTypeRef, consumer); } - get canFail(): boolean { + get canFail (): boolean { return false; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new ParseStringTransformer(this.graph, targetTypeRef, continuationTransformer); } else { return this.consumer.reverse( targetTypeRef, - new ParseStringTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer) + new ParseStringTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer), ); } } @@ -855,39 +868,39 @@ export class StringifyTransformer extends ProducerTransformer { return new StringifyTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - definedMap(this.consumer, xfer => xfer.reconstitute(builder)) + definedMap(this.consumer, xfer => xfer.reconstitute(builder)), ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; return other instanceof StringifyTransformer; } } export class MinMaxLengthCheckTransformer extends ProducerTransformer { - constructor( + constructor ( graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, readonly minLength: number | undefined, - readonly maxLength: number | undefined + readonly maxLength: number | undefined, ) { super("min-max-length-check", graph, sourceTypeRef, consumer); } - get canFail(): boolean { + get canFail (): boolean { return true; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new MinMaxLengthCheckTransformer( this.graph, targetTypeRef, continuationTransformer, this.minLength, - this.maxLength + this.maxLength, ); } else { return this.consumer.reverse( @@ -897,8 +910,8 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { this.consumer.sourceTypeRef, continuationTransformer, this.minLength, - this.maxLength - ) + this.maxLength, + ), ); } } @@ -909,11 +922,11 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), this.minLength, - this.maxLength + this.maxLength, ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; return ( other instanceof MinMaxLengthCheckTransformer && @@ -924,28 +937,28 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { } export class MinMaxValueTransformer extends ProducerTransformer { - constructor( + constructor ( graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, readonly minimum: number | undefined, - readonly maximum: number | undefined + readonly maximum: number | undefined, ) { super("min-max-value-check", graph, sourceTypeRef, consumer); } - get canFail(): boolean { + get canFail (): boolean { return true; } - reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new MinMaxValueTransformer( this.graph, targetTypeRef, continuationTransformer, this.minimum, - this.maximum + this.maximum, ); } else { return this.consumer.reverse( @@ -955,8 +968,8 @@ export class MinMaxValueTransformer extends ProducerTransformer { this.consumer.sourceTypeRef, continuationTransformer, this.minimum, - this.maximum - ) + this.maximum, + ), ); } } @@ -967,11 +980,11 @@ export class MinMaxValueTransformer extends ProducerTransformer { builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), this.minimum, - this.maximum + this.maximum, ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!super.equals(other)) return false; return ( other instanceof MinMaxValueTransformer && this.minimum === other.minimum && this.maximum === other.maximum @@ -980,29 +993,29 @@ export class MinMaxValueTransformer extends ProducerTransformer { } export class Transformation { - constructor( + constructor ( private readonly _graph: TypeGraph, private readonly _targetTypeRef: TypeRef, - readonly transformer: Transformer + readonly transformer: Transformer, ) {} - get sourceType(): Type { + get sourceType (): Type { return this.transformer.sourceType; } - get targetType(): Type { + get targetType (): Type { return derefTypeRef(this._targetTypeRef, this._graph); } - get reverse(): Transformation { + get reverse (): Transformation { return new Transformation( this._graph, this.transformer.sourceTypeRef, - this.transformer.reverse(this._targetTypeRef, undefined) + this.transformer.reverse(this._targetTypeRef, undefined), ); } - getChildren(): Set { + getChildren (): Set { return this.transformer.getChildren().add(this.targetType); } @@ -1010,41 +1023,41 @@ export class Transformation { return new Transformation( builder.typeGraph, builder.reconstituteTypeRef(this._targetTypeRef), - this.transformer.reconstitute(builder) + this.transformer.reconstitute(builder), ); } - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof Transformation)) return false; return this._targetTypeRef === other._targetTypeRef && this.transformer.equals(other.transformer); } - hashCode(): number { + hashCode (): number { let h = hashCodeOf(this._targetTypeRef); h = addHashCode(h, this.transformer.hashCode()); return h; } - debugPrint(): void { + debugPrint (): void { this.transformer.debugPrint(0); console.log(`-> ${debugStringForType(this.targetType)}`); } } class TransformationTypeAttributeKind extends TypeAttributeKind { - constructor() { + constructor () { super("transformation"); } - appliesToTypeKind(_kind: TypeKind): boolean { + appliesToTypeKind (_kind: TypeKind): boolean { return true; } - get inIdentity(): boolean { + get inIdentity (): boolean { return true; } - children(xf: Transformation): Set { + children (xf: Transformation): Set { return xf.getChildren(); } @@ -1052,18 +1065,18 @@ class TransformationTypeAttributeKind extends TypeAttributeKind return xf.reconstitute(builder); } - stringify(_: Transformation): string { + stringify (_: Transformation): string { return "transformation"; } } export const transformationTypeAttributeKind: TypeAttributeKind = new TransformationTypeAttributeKind(); -export function transformationForType(t: Type): Transformation | undefined { +export function transformationForType (t: Type): Transformation | undefined { return transformationTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } -export function followTargetType(t: Type): Type { +export function followTargetType (t: Type): Type { for (;;) { const xf = transformationForType(t); if (xf === undefined) return t; diff --git a/packages/quicktype-core/src/Type.ts b/packages/quicktype-core/src/Type.ts index 7a16f06d3..6c6542e08 100644 --- a/packages/quicktype-core/src/Type.ts +++ b/packages/quicktype-core/src/Type.ts @@ -18,15 +18,17 @@ import { hashCodeInit, addHashCode, hasOwnProperty, - mapFromObject + mapFromObject, } from "collection-utils"; import { defined, panic, assert } from "./support/Support"; -import { TypeReconstituter, BaseGraphRewriteBuilder } from "./GraphRewriting"; -import { TypeNames, namesTypeAttributeKind } from "./attributes/TypeNames"; -import { TypeAttributes } from "./attributes/TypeAttributes"; +import { type TypeReconstituter, type BaseGraphRewriteBuilder } from "./GraphRewriting"; +import { type TypeNames} from "./attributes/TypeNames"; +import { namesTypeAttributeKind } from "./attributes/TypeNames"; +import { type TypeAttributes } from "./attributes/TypeAttributes"; import { messageAssert } from "./Messages"; -import { TypeRef, attributesForTypeRef, derefTypeRef, TypeGraph, typeRefIndex } from "./TypeGraph"; +import { type TypeRef, type TypeGraph} from "./TypeGraph"; +import { attributesForTypeRef, derefTypeRef, typeRefIndex } from "./TypeGraph"; import { uriInferenceAttributesProducer } from "./attributes/URIAttributes"; /** @@ -37,11 +39,11 @@ import { uriInferenceAttributesProducer } from "./attributes/URIAttributes"; * For transformed type kinds that map to an existing primitive type, `primitive` * must specify that type kind. */ -export type TransformedStringTypeTargets = { +export interface TransformedStringTypeTargets { + attributesProducer?: (s: string) => TypeAttributes; jsonSchema: string; primitive: PrimitiveNonStringTypeKind | undefined; - attributesProducer?: (s: string) => TypeAttributes; -}; +} /** * All the transformed string type kinds and the JSON Schema formats and @@ -56,13 +58,13 @@ const transformedStringTypeTargetTypeKinds = { uuid: { jsonSchema: "uuid", primitive: undefined }, uri: { jsonSchema: "uri", primitive: undefined, attributesProducer: uriInferenceAttributesProducer }, "integer-string": { jsonSchema: "integer", primitive: "integer" } as TransformedStringTypeTargets, - "bool-string": { jsonSchema: "boolean", primitive: "bool" } as TransformedStringTypeTargets + "bool-string": { jsonSchema: "boolean", primitive: "bool" } as TransformedStringTypeTargets, }; export const transformedStringTypeTargetTypeKindsMap = mapFromObject( transformedStringTypeTargetTypeKinds as { - [kind: string]: TransformedStringTypeTargets; - } + [kind: string]: TransformedStringTypeTargets, + }, ); export type TransformedStringTypeKind = keyof typeof transformedStringTypeTargetTypeKinds; @@ -74,32 +76,32 @@ export type TypeKind = PrimitiveTypeKind | NamedTypeKind | "array" | "object" | export type ObjectTypeKind = "object" | "map" | "class"; export const transformedStringTypeKinds = new Set( - Object.getOwnPropertyNames(transformedStringTypeTargetTypeKinds) + Object.getOwnPropertyNames(transformedStringTypeTargetTypeKinds), ) as ReadonlySet; -export function isPrimitiveStringTypeKind(kind: string): kind is PrimitiveStringTypeKind { +export function isPrimitiveStringTypeKind (kind: string): kind is PrimitiveStringTypeKind { return kind === "string" || hasOwnProperty(transformedStringTypeTargetTypeKinds, kind); } -export function targetTypeKindForTransformedStringTypeKind( - kind: PrimitiveStringTypeKind +export function targetTypeKindForTransformedStringTypeKind ( + kind: PrimitiveStringTypeKind, ): PrimitiveNonStringTypeKind | undefined { const target = transformedStringTypeTargetTypeKindsMap.get(kind); if (target === undefined) return undefined; return target.primitive; } -export function isNumberTypeKind(kind: TypeKind): kind is "integer" | "double" { +export function isNumberTypeKind (kind: TypeKind): kind is "integer" | "double" { return kind === "integer" || kind === "double"; } -export function isPrimitiveTypeKind(kind: TypeKind): kind is PrimitiveTypeKind { +export function isPrimitiveTypeKind (kind: TypeKind): kind is PrimitiveTypeKind { if (isPrimitiveStringTypeKind(kind)) return true; if (isNumberTypeKind(kind)) return true; return kind === "none" || kind === "any" || kind === "null" || kind === "bool"; } -function triviallyStructurallyCompatible(x: Type, y: Type): boolean { +function triviallyStructurallyCompatible (x: Type, y: Type): boolean { if (x.index === y.index) return true; if (x.kind === "none" || y.kind === "none") return true; return false; @@ -108,16 +110,17 @@ function triviallyStructurallyCompatible(x: Type, y: Type): boolean { export class TypeIdentity { private readonly _hashCode: number; - constructor(private readonly _kind: TypeKind, private readonly _components: ReadonlyArray) { + constructor (private readonly _kind: TypeKind, private readonly _components: readonly any[]) { let h = hashCodeInit; h = addHashCode(h, hashCodeOf(this._kind)); for (const c of _components) { h = addHashCode(h, hashCodeOf(c)); } + this._hashCode = h; } - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof TypeIdentity)) return false; if (this._kind !== other._kind) return false; const n = this._components.length; @@ -125,10 +128,11 @@ export class TypeIdentity { for (let i = 0; i < n; i++) { if (!areEqual(this._components[i], other._components[i])) return false; } + return true; } - hashCode(): number { + hashCode (): number { return this._hashCode; } } @@ -139,72 +143,73 @@ export type MaybeTypeIdentity = TypeIdentity | undefined; export abstract class Type { abstract readonly kind: TypeKind; - constructor(readonly typeRef: TypeRef, protected readonly graph: TypeGraph) {} + constructor (readonly typeRef: TypeRef, protected readonly graph: TypeGraph) {} - get index(): number { + get index (): number { return typeRefIndex(this.typeRef); } // This must return a newly allocated set - abstract getNonAttributeChildren(): Set; + abstract getNonAttributeChildren (): Set; - getChildren(): ReadonlySet { + getChildren (): ReadonlySet { let result = this.getNonAttributeChildren(); for (const [k, v] of this.getAttributes()) { if (k.children === undefined) continue; setUnionInto(result, k.children(v)); } + return result; } - getAttributes(): TypeAttributes { + getAttributes (): TypeAttributes { return attributesForTypeRef(this.typeRef, this.graph); } - get hasNames(): boolean { + get hasNames (): boolean { return namesTypeAttributeKind.tryGetInAttributes(this.getAttributes()) !== undefined; } - getNames(): TypeNames { + getNames (): TypeNames { return defined(namesTypeAttributeKind.tryGetInAttributes(this.getAttributes())); } - getCombinedName(): string { + getCombinedName (): string { return this.getNames().combinedName; } - abstract get isNullable(): boolean; + abstract get isNullable (): boolean; // FIXME: Remove `isPrimitive` - abstract isPrimitive(): this is PrimitiveType; - abstract get identity(): MaybeTypeIdentity; + abstract isPrimitive (): this is PrimitiveType; + abstract get identity (): MaybeTypeIdentity; abstract reconstitute( builder: TypeReconstituter, canonicalOrder: boolean ): void; - get debugPrintKind(): string { + get debugPrintKind (): string { return this.kind; } - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof Type)) return false; return this.typeRef === other.typeRef; } - hashCode(): number { + hashCode (): number { return hashCodeOf(this.typeRef); } // This will only ever be called when `this` and `other` are not // equal, but `this.kind === other.kind`. - protected abstract structuralEqualityStep( + protected abstract structuralEqualityStep ( other: Type, conflateNumbers: boolean, queue: (a: Type, b: Type) => boolean ): boolean; - structurallyCompatible(other: Type, conflateNumbers = false): boolean { - function kindsCompatible(kind1: TypeKind, kind2: TypeKind): boolean { + structurallyCompatible (other: Type, conflateNumbers = false): boolean { + function kindsCompatible (kind1: TypeKind, kind2: TypeKind): boolean { if (kind1 === kind2) return true; if (!conflateNumbers) return false; if (kind1 === "integer") return kind2 === "double"; @@ -215,11 +220,11 @@ export abstract class Type { if (triviallyStructurallyCompatible(this, other)) return true; if (!kindsCompatible(this.kind, other.kind)) return false; - const workList: [Type, Type][] = [[this, other]]; + const workList: Array<[Type, Type]> = [[this, other]]; // This contains a set of pairs which are the type pairs // we have already determined to be equal. We can't just // do comparison recursively because types can have cycles. - const done: [number, number][] = []; + const done: Array<[number, number]> = []; let failed: boolean; const queue = (x: Type, y: Type): boolean => { @@ -228,6 +233,7 @@ export abstract class Type { failed = true; return false; } + workList.push([x, y]); return true; }; @@ -249,6 +255,7 @@ export abstract class Type { break; } } + if (found) continue; done.push([ai, bi]); } @@ -261,11 +268,11 @@ export abstract class Type { return true; } - getParentTypes(): ReadonlySet { + getParentTypes (): ReadonlySet { return this.graph.getParentsOfType(this); } - getAncestorsNotInSet(set: ReadonlySet): ReadonlySet { + getAncestorsNotInSet (set: ReadonlySet): ReadonlySet { const workList: Type[] = [this]; const processed = new Set(); const ancestors = new Set(); @@ -287,41 +294,42 @@ export abstract class Type { } } } + return ancestors; } } -function hasUniqueIdentityAttributes(attributes: TypeAttributes): boolean { +function hasUniqueIdentityAttributes (attributes: TypeAttributes): boolean { return mapSome(attributes, (v, ta) => ta.requiresUniqueIdentity(v)); } -function identityAttributes(attributes: TypeAttributes): TypeAttributes { +function identityAttributes (attributes: TypeAttributes): TypeAttributes { return mapFilter(attributes, (_, kind) => kind.inIdentity); } -export function primitiveTypeIdentity(kind: PrimitiveTypeKind, attributes: TypeAttributes): MaybeTypeIdentity { +export function primitiveTypeIdentity (kind: PrimitiveTypeKind, attributes: TypeAttributes): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity(kind, [identityAttributes(attributes)]); } export class PrimitiveType extends Type { - constructor(typeRef: TypeRef, graph: TypeGraph, public readonly kind: PrimitiveTypeKind) { + constructor (typeRef: TypeRef, graph: TypeGraph, public readonly kind: PrimitiveTypeKind) { super(typeRef, graph); } - get isNullable(): boolean { + get isNullable (): boolean { return this.kind === "null" || this.kind === "any" || this.kind === "none"; } - isPrimitive(): this is PrimitiveType { + isPrimitive (): this is PrimitiveType { return true; } - getNonAttributeChildren(): Set { + getNonAttributeChildren (): Set { return new Set(); } - get identity(): MaybeTypeIdentity { + get identity (): MaybeTypeIdentity { return primitiveTypeIdentity(this.kind, this.getAttributes()); } @@ -329,16 +337,16 @@ export class PrimitiveType extends Type { builder.getPrimitiveType(this.kind); } - protected structuralEqualityStep( + protected structuralEqualityStep ( _other: Type, _conflateNumbers: boolean, - _queue: (a: Type, b: Type) => boolean + _queue: (a: Type, b: Type) => boolean, ): boolean { return true; } } -export function arrayTypeIdentity(attributes: TypeAttributes, itemsRef: TypeRef): MaybeTypeIdentity { +export function arrayTypeIdentity (attributes: TypeAttributes, itemsRef: TypeRef): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity("array", [identityAttributes(attributes), itemsRef]); } @@ -346,41 +354,43 @@ export function arrayTypeIdentity(attributes: TypeAttributes, itemsRef: TypeRef) export class ArrayType extends Type { public readonly kind = "array"; - constructor(typeRef: TypeRef, graph: TypeGraph, private _itemsRef?: TypeRef) { + constructor (typeRef: TypeRef, graph: TypeGraph, private _itemsRef?: TypeRef) { super(typeRef, graph); } - setItems(itemsRef: TypeRef) { + setItems (itemsRef: TypeRef) { if (this._itemsRef !== undefined) { return panic("Can only set array items once"); } + this._itemsRef = itemsRef; } - private getItemsRef(): TypeRef { + private getItemsRef (): TypeRef { if (this._itemsRef === undefined) { return panic("Array items accessed before they were set"); } + return this._itemsRef; } - get items(): Type { + get items (): Type { return derefTypeRef(this.getItemsRef(), this.graph); } - getNonAttributeChildren(): Set { + getNonAttributeChildren (): Set { return new Set([this.items]); } - get isNullable(): boolean { + get isNullable (): boolean { return false; } - isPrimitive(): this is PrimitiveType { + isPrimitive (): this is PrimitiveType { return false; } - get identity(): MaybeTypeIdentity { + get identity (): MaybeTypeIdentity { return arrayTypeIdentity(this.getAttributes(), this.getItemsRef()); } @@ -395,76 +405,77 @@ export class ArrayType extends Type { } } - protected structuralEqualityStep( + protected structuralEqualityStep ( other: ArrayType, _conflateNumbers: boolean, - queue: (a: Type, b: Type) => boolean + queue: (a: Type, b: Type) => boolean, ): boolean { return queue(this.items, other.items); } } export class GenericClassProperty { - constructor(readonly typeData: T, readonly isOptional: boolean) {} + constructor (readonly typeData: T, readonly isOptional: boolean) {} - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof GenericClassProperty)) { return false; } + return areEqual(this.typeData, other.typeData) && this.isOptional === other.isOptional; } - hashCode(): number { + hashCode (): number { return hashCodeOf(this.typeData) + (this.isOptional ? 17 : 23); } } export class ClassProperty extends GenericClassProperty { - constructor(typeRef: TypeRef, readonly graph: TypeGraph, isOptional: boolean) { + constructor (typeRef: TypeRef, readonly graph: TypeGraph, isOptional: boolean) { super(typeRef, isOptional); } - get typeRef(): TypeRef { + get typeRef (): TypeRef { return this.typeData; } - get type(): Type { + get type (): Type { return derefTypeRef(this.typeRef, this.graph); } } -function objectTypeIdentify( +function objectTypeIdentify ( kind: ObjectTypeKind, attributes: TypeAttributes, properties: ReadonlyMap, - additionalPropertiesRef: TypeRef | undefined + additionalPropertiesRef: TypeRef | undefined, ): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity(kind, [identityAttributes(attributes), properties, additionalPropertiesRef]); } -export function classTypeIdentity( +export function classTypeIdentity ( attributes: TypeAttributes, - properties: ReadonlyMap + properties: ReadonlyMap, ): MaybeTypeIdentity { return objectTypeIdentify("class", attributes, properties, undefined); } -export function mapTypeIdentify( +export function mapTypeIdentify ( attributes: TypeAttributes, - additionalPropertiesRef: TypeRef | undefined + additionalPropertiesRef: TypeRef | undefined, ): MaybeTypeIdentity { return objectTypeIdentify("map", attributes, new Map(), additionalPropertiesRef); } export class ObjectType extends Type { - constructor( + constructor ( typeRef: TypeRef, graph: TypeGraph, public readonly kind: ObjectTypeKind, readonly isFixed: boolean, private _properties: ReadonlyMap | undefined, - private _additionalPropertiesRef: TypeRef | undefined + private _additionalPropertiesRef: TypeRef | undefined, ) { super(typeRef, graph); @@ -472,6 +483,7 @@ export class ObjectType extends Type { if (_properties !== undefined) { assert(_properties.size === 0); } + assert(!isFixed); } else if (kind === "class") { assert(_additionalPropertiesRef === undefined); @@ -480,7 +492,7 @@ export class ObjectType extends Type { } } - setProperties(properties: ReadonlyMap, additionalPropertiesRef: TypeRef | undefined) { + setProperties (properties: ReadonlyMap, additionalPropertiesRef: TypeRef | undefined) { assert(this._properties === undefined, "Tried to set object properties twice"); if (this instanceof MapType) { @@ -495,49 +507,50 @@ export class ObjectType extends Type { this._additionalPropertiesRef = additionalPropertiesRef; } - getProperties(): ReadonlyMap { + getProperties (): ReadonlyMap { return defined(this._properties); } - getSortedProperties(): ReadonlyMap { + getSortedProperties (): ReadonlyMap { return mapSortByKey(this.getProperties()); } - private getAdditionalPropertiesRef(): TypeRef | undefined { + private getAdditionalPropertiesRef (): TypeRef | undefined { assert(this._properties !== undefined, "Properties are not set yet"); return this._additionalPropertiesRef; } - getAdditionalProperties(): Type | undefined { + getAdditionalProperties (): Type | undefined { const tref = this.getAdditionalPropertiesRef(); if (tref === undefined) return undefined; return derefTypeRef(tref, this.graph); } - getNonAttributeChildren(): Set { + getNonAttributeChildren (): Set { const types = mapSortToArray(this.getProperties(), (_, k) => k).map(([_, p]) => p.type); const additionalProperties = this.getAdditionalProperties(); if (additionalProperties !== undefined) { types.push(additionalProperties); } + return new Set(types); } - get isNullable(): boolean { + get isNullable (): boolean { return false; } - isPrimitive(): this is PrimitiveType { + isPrimitive (): this is PrimitiveType { return false; } - get identity(): MaybeTypeIdentity { + get identity (): MaybeTypeIdentity { if (this.isFixed) return undefined; return objectTypeIdentify( this.kind, this.getAttributes(), this.getProperties(), - this.getAdditionalPropertiesRef() + this.getAdditionalPropertiesRef(), ); } @@ -552,7 +565,7 @@ export class ObjectType extends Type { (maybeAdditionalProperties !== undefined || this._additionalPropertiesRef === undefined) ) { const properties = mapMap(propertiesInNewOrder, (cp, n) => - builder.makeClassProperty(defined(maybePropertyTypes.get(n)), cp.isOptional) + builder.makeClassProperty(defined(maybePropertyTypes.get(n)), cp.isOptional), ); switch (this.kind) { @@ -569,6 +582,7 @@ export class ObjectType extends Type { } else { builder.getClassType(properties); } + break; default: return panic(`Invalid object type kind ${this.kind}`); @@ -591,17 +605,17 @@ export class ObjectType extends Type { const reconstitutedTypes = mapMap(sortedProperties, cp => builder.reconstitute(cp.typeRef)); const properties = mapMap(propertiesInNewOrder, (cp, n) => - builder.makeClassProperty(defined(reconstitutedTypes.get(n)), cp.isOptional) + builder.makeClassProperty(defined(reconstitutedTypes.get(n)), cp.isOptional), ); const additionalProperties = definedMap(this._additionalPropertiesRef, r => builder.reconstitute(r)); builder.setObjectProperties(properties, additionalProperties); } } - protected structuralEqualityStep( + protected structuralEqualityStep ( other: ObjectType, _conflateNumbers: boolean, - queue: (a: Type, b: Type) => boolean + queue: (a: Type, b: Type) => boolean, ): boolean { const pa = this.getProperties(); const pb = other.getProperties(); @@ -614,46 +628,47 @@ export class ObjectType extends Type { return false; } } + if (failed) return false; const thisAdditionalProperties = this.getAdditionalProperties(); const otherAdditionalProperties = other.getAdditionalProperties(); - if ((thisAdditionalProperties === undefined) !== (otherAdditionalProperties === undefined)) return false; + if (thisAdditionalProperties === undefined !== (otherAdditionalProperties === undefined)) return false; if (thisAdditionalProperties === undefined || otherAdditionalProperties === undefined) return true; return queue(thisAdditionalProperties, otherAdditionalProperties); } } export class ClassType extends ObjectType { - constructor( + constructor ( typeRef: TypeRef, graph: TypeGraph, isFixed: boolean, - properties: ReadonlyMap | undefined + properties: ReadonlyMap | undefined, ) { super(typeRef, graph, "class", isFixed, properties, undefined); } } export class MapType extends ObjectType { - constructor(typeRef: TypeRef, graph: TypeGraph, valuesRef: TypeRef | undefined) { + constructor (typeRef: TypeRef, graph: TypeGraph, valuesRef: TypeRef | undefined) { super( typeRef, graph, "map", false, definedMap(valuesRef, () => new Map()), - valuesRef + valuesRef, ); } // FIXME: Remove and use `getAdditionalProperties()` instead. - get values(): Type { + get values (): Type { return defined(this.getAdditionalProperties()); } } -export function enumTypeIdentity(attributes: TypeAttributes, cases: ReadonlySet): MaybeTypeIdentity { +export function enumTypeIdentity (attributes: TypeAttributes, cases: ReadonlySet): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity("enum", [identityAttributes(attributes), cases]); } @@ -661,23 +676,23 @@ export function enumTypeIdentity(attributes: TypeAttributes, cases: ReadonlySet< export class EnumType extends Type { public readonly kind = "enum"; - constructor(typeRef: TypeRef, graph: TypeGraph, readonly cases: ReadonlySet) { + constructor (typeRef: TypeRef, graph: TypeGraph, readonly cases: ReadonlySet) { super(typeRef, graph); } - get isNullable(): boolean { + get isNullable (): boolean { return false; } - isPrimitive(): this is PrimitiveType { + isPrimitive (): this is PrimitiveType { return false; } - get identity(): MaybeTypeIdentity { + get identity (): MaybeTypeIdentity { return enumTypeIdentity(this.getAttributes(), this.cases); } - getNonAttributeChildren(): Set { + getNonAttributeChildren (): Set { return new Set(); } @@ -685,20 +700,20 @@ export class EnumType extends Type { builder.getEnumType(this.cases); } - protected structuralEqualityStep( + protected structuralEqualityStep ( other: EnumType, _conflateNumbers: boolean, - _queue: (a: Type, b: Type) => void + _queue: (a: Type, b: Type) => void, ): boolean { return areEqual(this.cases, other.cases); } } -export function setOperationCasesEqual( +export function setOperationCasesEqual ( typesA: Iterable, typesB: Iterable, conflateNumbers: boolean, - membersEqual: (a: Type, b: Type) => boolean + membersEqual: (a: Type, b: Type) => boolean, ): boolean { const ma = toReadonlySet(typesA); const mb = toReadonlySet(typesB); @@ -708,83 +723,87 @@ export function setOperationCasesEqual( if (tb !== undefined) { if (membersEqual(ta, tb)) return true; } + if (conflateNumbers) { if (ta.kind === "integer" && iterableSome(mb, t => t.kind === "double")) return true; if (ta.kind === "double" && iterableSome(mb, t => t.kind === "integer")) return true; } + return false; }); } -export function setOperationTypeIdentity( +export function setOperationTypeIdentity ( kind: TypeKind, attributes: TypeAttributes, - memberRefs: ReadonlySet + memberRefs: ReadonlySet, ): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity(kind, [identityAttributes(attributes), memberRefs]); } -export function unionTypeIdentity(attributes: TypeAttributes, memberRefs: ReadonlySet): MaybeTypeIdentity { +export function unionTypeIdentity (attributes: TypeAttributes, memberRefs: ReadonlySet): MaybeTypeIdentity { return setOperationTypeIdentity("union", attributes, memberRefs); } -export function intersectionTypeIdentity( +export function intersectionTypeIdentity ( attributes: TypeAttributes, - memberRefs: ReadonlySet + memberRefs: ReadonlySet, ): MaybeTypeIdentity { return setOperationTypeIdentity("intersection", attributes, memberRefs); } export abstract class SetOperationType extends Type { - constructor( + constructor ( typeRef: TypeRef, graph: TypeGraph, public readonly kind: TypeKind, - private _memberRefs?: ReadonlySet + private _memberRefs?: ReadonlySet, ) { super(typeRef, graph); } - setMembers(memberRefs: ReadonlySet): void { + setMembers (memberRefs: ReadonlySet): void { if (this._memberRefs !== undefined) { return panic("Can only set map members once"); } + this._memberRefs = memberRefs; } - protected getMemberRefs(): ReadonlySet { + protected getMemberRefs (): ReadonlySet { if (this._memberRefs === undefined) { return panic("Map members accessed before they were set"); } + return this._memberRefs; } - get members(): ReadonlySet { + get members (): ReadonlySet { return setMap(this.getMemberRefs(), tref => derefTypeRef(tref, this.graph)); } - get sortedMembers(): ReadonlySet { + get sortedMembers (): ReadonlySet { return this.getNonAttributeChildren(); } - getNonAttributeChildren(): Set { + getNonAttributeChildren (): Set { // FIXME: We're assuming no two members of the same kind. return setSortBy(this.members, t => t.kind); } - isPrimitive(): this is PrimitiveType { + isPrimitive (): this is PrimitiveType { return false; } - get identity(): MaybeTypeIdentity { + get identity (): MaybeTypeIdentity { return setOperationTypeIdentity(this.kind, this.getAttributes(), this.getMemberRefs()); } protected reconstituteSetOperation( builder: TypeReconstituter, canonicalOrder: boolean, - getType: (members: ReadonlySet | undefined) => void + getType: (members: ReadonlySet | undefined) => void, ): void { const sortedMemberRefs = mapMap(this.sortedMembers.entries(), t => t.typeRef); const membersInOrder = canonicalOrder ? this.sortedMembers : this.members; @@ -798,21 +817,21 @@ export abstract class SetOperationType extends Type { } } - protected structuralEqualityStep( + protected structuralEqualityStep ( other: SetOperationType, conflateNumbers: boolean, - queue: (a: Type, b: Type) => boolean + queue: (a: Type, b: Type) => boolean, ): boolean { return setOperationCasesEqual(this.members, other.members, conflateNumbers, queue); } } export class IntersectionType extends SetOperationType { - constructor(typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { + constructor (typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { super(typeRef, graph, "intersection", memberRefs); } - get isNullable(): boolean { + get isNullable (): boolean { return panic("isNullable not implemented for IntersectionType"); } @@ -828,31 +847,31 @@ export class IntersectionType extends SetOperationType { } export class UnionType extends SetOperationType { - constructor(typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { + constructor (typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { super(typeRef, graph, "union", memberRefs); if (memberRefs !== undefined) { messageAssert(memberRefs.size > 0, "IRNoEmptyUnions", {}); } } - setMembers(memberRefs: ReadonlySet): void { + setMembers (memberRefs: ReadonlySet): void { messageAssert(memberRefs.size > 0, "IRNoEmptyUnions", {}); super.setMembers(memberRefs); } - get stringTypeMembers(): ReadonlySet { + get stringTypeMembers (): ReadonlySet { return setFilter(this.members, t => isPrimitiveStringTypeKind(t.kind) || t.kind === "enum"); } - findMember(kind: TypeKind): Type | undefined { + findMember (kind: TypeKind): Type | undefined { return iterableFind(this.members, t => t.kind === kind); } - get isNullable(): boolean { + get isNullable (): boolean { return this.findMember("null") !== undefined; } - get isCanonical(): boolean { + get isCanonical (): boolean { const members = this.members; if (members.size <= 1) return false; const kinds = setMap(members, t => t.kind); diff --git a/packages/quicktype-core/src/TypeBuilder.ts b/packages/quicktype-core/src/TypeBuilder.ts index d7d0a4b59..55d521857 100644 --- a/packages/quicktype-core/src/TypeBuilder.ts +++ b/packages/quicktype-core/src/TypeBuilder.ts @@ -8,19 +8,25 @@ import { areEqual, setUnionManyInto, definedMap, - withDefault + withDefault, } from "collection-utils"; import { - PrimitiveTypeKind, - Type, + type PrimitiveTypeKind, + type Type, + type PrimitiveStringTypeKind, + type MaybeTypeIdentity, + type TypeIdentity, + type TransformedStringTypeKind, + type TypeKind, +} from "./Type"; +import { PrimitiveType, EnumType, MapType, ArrayType, ClassType, UnionType, - PrimitiveStringTypeKind, ClassProperty, IntersectionType, ObjectType, @@ -31,19 +37,17 @@ import { classTypeIdentity, unionTypeIdentity, intersectionTypeIdentity, - MaybeTypeIdentity, - TypeIdentity, - TransformedStringTypeKind, isPrimitiveStringTypeKind, transformedStringTypeKinds, - TypeKind } from "./Type"; -import { TypeGraph, TypeRef, makeTypeRef, derefTypeRef, typeRefIndex, assertTypeRefGraph } from "./TypeGraph"; +import { type TypeRef} from "./TypeGraph"; +import { TypeGraph, makeTypeRef, derefTypeRef, typeRefIndex, assertTypeRefGraph } from "./TypeGraph"; +import { + type TypeAttributes} from "./attributes/TypeAttributes"; import { - TypeAttributes, combineTypeAttributes, TypeAttributeKind, - emptyTypeAttributes + emptyTypeAttributes, } from "./attributes/TypeAttributes"; import { defined, assert, panic } from "./support/Support"; import { stringTypesTypeAttributeKind, StringTypes } from "./attributes/StringTypes"; @@ -51,23 +55,23 @@ import { stringTypesTypeAttributeKind, StringTypes } from "./attributes/StringTy // FIXME: Don't infer provenance. All original types should be present in // non-inferred form in the final graph. class ProvenanceTypeAttributeKind extends TypeAttributeKind> { - constructor() { + constructor () { super("provenance"); } - appliesToTypeKind(_kind: TypeKind): boolean { + appliesToTypeKind (_kind: TypeKind): boolean { return true; } - combine(arr: Set[]): Set { + combine (arr: Array>): Set { return setUnionManyInto(new Set(), arr); } - makeInferred(p: Set): Set { + makeInferred (p: Set): Set { return p; } - stringify(p: Set): string { + stringify (p: Set): string { return Array.from(p) .sort() .map(i => i.toString()) @@ -79,7 +83,7 @@ export const provenanceTypeAttributeKind: TypeAttributeKind> = new P export type StringTypeMapping = ReadonlyMap; -export function stringTypeMappingGet(stm: StringTypeMapping, kind: TransformedStringTypeKind): PrimitiveStringTypeKind { +export function stringTypeMappingGet (stm: StringTypeMapping, kind: TransformedStringTypeKind): PrimitiveStringTypeKind { const mapped = stm.get(kind); if (mapped === undefined) return "string"; return mapped; @@ -87,14 +91,15 @@ export function stringTypeMappingGet(stm: StringTypeMapping, kind: TransformedSt let noStringTypeMapping: StringTypeMapping | undefined; -export function getNoStringTypeMapping(): StringTypeMapping { +export function getNoStringTypeMapping (): StringTypeMapping { if (noStringTypeMapping === undefined) { noStringTypeMapping = new Map( Array.from(transformedStringTypeKinds).map( - k => [k, k] as [TransformedStringTypeKind, PrimitiveStringTypeKind] - ) + k => [k, k] as [TransformedStringTypeKind, PrimitiveStringTypeKind], + ), ); } + return noStringTypeMapping; } @@ -102,37 +107,39 @@ export class TypeBuilder { readonly typeGraph: TypeGraph; protected readonly topLevels: Map = new Map(); - protected readonly types: (Type | undefined)[] = []; + + protected readonly types: Array = []; + private readonly typeAttributes: TypeAttributes[] = []; private _addedForwardingIntersection = false; - constructor( + constructor ( typeGraphSerial: number, private readonly _stringTypeMapping: StringTypeMapping, readonly canonicalOrder: boolean, private readonly _allPropertiesOptional: boolean, private readonly _addProvenanceAttributes: boolean, - inheritsProvenanceAttributes: boolean + inheritsProvenanceAttributes: boolean, ) { assert( !_addProvenanceAttributes || !inheritsProvenanceAttributes, - "We can't both inherit as well as add provenance" + "We can't both inherit as well as add provenance", ); this.typeGraph = new TypeGraph(this, typeGraphSerial, _addProvenanceAttributes || inheritsProvenanceAttributes); } - addTopLevel(name: string, tref: TypeRef): void { + addTopLevel (name: string, tref: TypeRef): void { // assert(t.typeGraph === this.typeGraph, "Adding top-level to wrong type graph"); assert(!this.topLevels.has(name), "Trying to add top-level with existing name"); assert( this.types[typeRefIndex(tref)] !== undefined, - "Trying to add a top-level type that doesn't exist (yet?)" + "Trying to add a top-level type that doesn't exist (yet?)", ); this.topLevels.set(name, tref); } - reserveTypeRef(): TypeRef { + reserveTypeRef (): TypeRef { const index = this.types.length; // console.log(`reserving ${index}`); this.types.push(undefined); @@ -144,25 +151,26 @@ export class TypeBuilder { return tref; } - private assertTypeRefGraph(tref: TypeRef | undefined): void { + private assertTypeRefGraph (tref: TypeRef | undefined): void { if (tref === undefined) return; assertTypeRefGraph(tref, this.typeGraph); } - private assertTypeRefSetGraph(trefs: ReadonlySet | undefined): void { + private assertTypeRefSetGraph (trefs: ReadonlySet | undefined): void { if (trefs === undefined) return; trefs.forEach(tref => this.assertTypeRefGraph(tref)); } - private filterTypeAttributes(t: Type, attributes: TypeAttributes): TypeAttributes { + private filterTypeAttributes (t: Type, attributes: TypeAttributes): TypeAttributes { const filtered = mapFilter(attributes, (_, k) => k.appliesToTypeKind(t.kind)); if (attributes.size !== filtered.size) { this.setLostTypeAttributes(); } + return filtered; } - private commitType(tref: TypeRef, t: Type): void { + private commitType (tref: TypeRef, t: Type): void { this.assertTypeRefGraph(tref); const index = typeRefIndex(tref); // const name = names !== undefined ? ` ${names.combinedName}` : ""; @@ -175,37 +183,40 @@ export class TypeBuilder { protected addType( forwardingRef: TypeRef | undefined, creator: (tref: TypeRef) => T, - attributes: TypeAttributes | undefined + attributes: TypeAttributes | undefined, ): TypeRef { if (forwardingRef !== undefined) { this.assertTypeRefGraph(forwardingRef); assert(this.types[typeRefIndex(forwardingRef)] === undefined); } + const tref = forwardingRef !== undefined ? forwardingRef : this.reserveTypeRef(); if (attributes !== undefined) { const index = typeRefIndex(tref); this.typeAttributes[index] = combineTypeAttributes("union", this.typeAttributes[index], attributes); } + const t = creator(tref); this.commitType(tref, t); return tref; } - typeAtIndex(index: number): Type { + typeAtIndex (index: number): Type { const maybeType = this.types[index]; if (maybeType === undefined) { return panic("Trying to deref an undefined type in a type builder"); } + return maybeType; } - atIndex(index: number): [Type, TypeAttributes] { + atIndex (index: number): [Type, TypeAttributes] { const t = this.typeAtIndex(index); const attribtues = this.typeAttributes[index]; return [t, attribtues]; } - addAttributes(tref: TypeRef, attributes: TypeAttributes): void { + addAttributes (tref: TypeRef, attributes: TypeAttributes): void { this.assertTypeRefGraph(tref); const index = typeRefIndex(tref); const existingAttributes = this.typeAttributes[index]; @@ -216,56 +227,57 @@ export class TypeBuilder { if (existing === undefined) return false; return areEqual(existing, v); }), - "Can't add different identity type attributes to an existing type" + "Can't add different identity type attributes to an existing type", ); const maybeType = this.types[index]; if (maybeType !== undefined) { attributes = this.filterTypeAttributes(maybeType, attributes); } + const nonIdentityAttributes = mapFilter(attributes, (_, k) => !k.inIdentity); this.typeAttributes[index] = combineTypeAttributes("union", existingAttributes, nonIdentityAttributes); } - finish(): TypeGraph { + finish (): TypeGraph { this.typeGraph.freeze(this.topLevels, this.types.map(defined), this.typeAttributes); return this.typeGraph; } - protected addForwardingIntersection(forwardingRef: TypeRef, tref: TypeRef): TypeRef { + protected addForwardingIntersection (forwardingRef: TypeRef, tref: TypeRef): TypeRef { this.assertTypeRefGraph(tref); this._addedForwardingIntersection = true; return this.addType(forwardingRef, tr => new IntersectionType(tr, this.typeGraph, new Set([tref])), undefined); } - protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: undefined): undefined; - protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: TypeRef): TypeRef; - protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined; - protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined { + protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: undefined): undefined; + protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: TypeRef): TypeRef; + protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined; + protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined { if (tref === undefined) return undefined; if (forwardingRef === undefined) return tref; return this.addForwardingIntersection(forwardingRef, tref); } - get didAddForwardingIntersection(): boolean { + get didAddForwardingIntersection (): boolean { return this._addedForwardingIntersection; } private readonly _typeForIdentity: EqualityMap = new EqualityMap(); - private registerTypeForIdentity(identity: MaybeTypeIdentity, tref: TypeRef): void { + private registerTypeForIdentity (identity: MaybeTypeIdentity, tref: TypeRef): void { if (identity === undefined) return; this._typeForIdentity.set(identity, tref); } - protected makeIdentity(maker: () => MaybeTypeIdentity): MaybeTypeIdentity { + protected makeIdentity (maker: () => MaybeTypeIdentity): MaybeTypeIdentity { return maker(); } - private getOrAddType( + private getOrAddType ( identityMaker: () => MaybeTypeIdentity, creator: (tr: TypeRef) => Type, attributes: TypeAttributes | undefined, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { const identity = this.makeIdentity(identityMaker); let maybeTypeRef: TypeRef | undefined; @@ -274,6 +286,7 @@ export class TypeBuilder { } else { maybeTypeRef = this._typeForIdentity.get(identity); } + if (maybeTypeRef !== undefined) { const result = this.forwardIfNecessary(forwardingRef, maybeTypeRef); if (attributes !== undefined) { @@ -283,9 +296,10 @@ export class TypeBuilder { // asserts that no identity attributes are added later. this.addAttributes( result, - mapFilter(attributes, (_, k) => !k.inIdentity) + mapFilter(attributes, (_, k) => !k.inIdentity), ); } + return result; } @@ -294,11 +308,11 @@ export class TypeBuilder { return tref; } - private registerType(t: Type): void { + private registerType (t: Type): void { this.registerTypeForIdentity(t.identity, t.typeRef); } - getPrimitiveType(kind: PrimitiveTypeKind, maybeAttributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { + getPrimitiveType (kind: PrimitiveTypeKind, maybeAttributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { const attributes = withDefault(maybeAttributes, emptyTypeAttributes); // FIXME: Why do date/time types need a StringTypes attribute? // FIXME: Remove this from here and put it into flattenStrings @@ -306,56 +320,59 @@ export class TypeBuilder { if (isPrimitiveStringTypeKind(kind) && kind !== "string") { kind = stringTypeMappingGet(this._stringTypeMapping, kind); } + if (kind === "string") { return this.getStringType(attributes, stringTypes, forwardingRef); } + return this.getOrAddType( () => primitiveTypeIdentity(kind, attributes), tr => new PrimitiveType(tr, this.typeGraph, kind), attributes, - forwardingRef + forwardingRef, ); } - getStringType(attributes: TypeAttributes, stringTypes: StringTypes | undefined, forwardingRef?: TypeRef): TypeRef { + getStringType (attributes: TypeAttributes, stringTypes: StringTypes | undefined, forwardingRef?: TypeRef): TypeRef { const existingStringTypes = mapFind(attributes, (_, k) => k === stringTypesTypeAttributeKind); assert( - (stringTypes === undefined) !== (existingStringTypes === undefined), - "Must instantiate string type with one enum case attribute" + stringTypes === undefined !== (existingStringTypes === undefined), + "Must instantiate string type with one enum case attribute", ); if (existingStringTypes === undefined) { attributes = combineTypeAttributes( "union", attributes, - stringTypesTypeAttributeKind.makeAttributes(defined(stringTypes)) + stringTypesTypeAttributeKind.makeAttributes(defined(stringTypes)), ); } + return this.getOrAddType( () => primitiveTypeIdentity("string", attributes), tr => new PrimitiveType(tr, this.typeGraph, "string"), attributes, - forwardingRef + forwardingRef, ); } - getEnumType(attributes: TypeAttributes, cases: ReadonlySet, forwardingRef?: TypeRef): TypeRef { + getEnumType (attributes: TypeAttributes, cases: ReadonlySet, forwardingRef?: TypeRef): TypeRef { return this.getOrAddType( () => enumTypeIdentity(attributes, cases), tr => new EnumType(tr, this.typeGraph, cases), attributes, - forwardingRef + forwardingRef, ); } - makeClassProperty(tref: TypeRef, isOptional: boolean): ClassProperty { + makeClassProperty (tref: TypeRef, isOptional: boolean): ClassProperty { return new ClassProperty(tref, this.typeGraph, isOptional); } - getUniqueObjectType( + getUniqueObjectType ( attributes: TypeAttributes, properties: ReadonlyMap | undefined, additionalProperties: TypeRef | undefined, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { this.assertTypeRefGraph(additionalProperties); @@ -363,29 +380,29 @@ export class TypeBuilder { return this.addType( forwardingRef, tref => new ObjectType(tref, this.typeGraph, "object", true, properties, additionalProperties), - attributes + attributes, ); } - getUniqueMapType(forwardingRef?: TypeRef): TypeRef { + getUniqueMapType (forwardingRef?: TypeRef): TypeRef { return this.addType(forwardingRef, tr => new MapType(tr, this.typeGraph, undefined), undefined); } - getMapType(attributes: TypeAttributes, values: TypeRef, forwardingRef?: TypeRef): TypeRef { + getMapType (attributes: TypeAttributes, values: TypeRef, forwardingRef?: TypeRef): TypeRef { this.assertTypeRefGraph(values); return this.getOrAddType( () => mapTypeIdentify(attributes, values), tr => new MapType(tr, this.typeGraph, values), attributes, - forwardingRef + forwardingRef, ); } - setObjectProperties( + setObjectProperties ( ref: TypeRef, properties: ReadonlyMap, - additionalProperties: TypeRef | undefined + additionalProperties: TypeRef | undefined, ): void { this.assertTypeRefGraph(additionalProperties); @@ -393,134 +410,139 @@ export class TypeBuilder { if (!(type instanceof ObjectType)) { return panic("Tried to set properties of non-object type"); } + type.setProperties(this.modifyPropertiesIfNecessary(properties), additionalProperties); this.registerType(type); } - getUniqueArrayType(forwardingRef?: TypeRef): TypeRef { + getUniqueArrayType (forwardingRef?: TypeRef): TypeRef { return this.addType(forwardingRef, tr => new ArrayType(tr, this.typeGraph, undefined), undefined); } - getArrayType(attributes: TypeAttributes, items: TypeRef, forwardingRef?: TypeRef): TypeRef { + getArrayType (attributes: TypeAttributes, items: TypeRef, forwardingRef?: TypeRef): TypeRef { this.assertTypeRefGraph(items); return this.getOrAddType( () => arrayTypeIdentity(attributes, items), tr => new ArrayType(tr, this.typeGraph, items), attributes, - forwardingRef + forwardingRef, ); } - setArrayItems(ref: TypeRef, items: TypeRef): void { + setArrayItems (ref: TypeRef, items: TypeRef): void { this.assertTypeRefGraph(items); const type = derefTypeRef(ref, this.typeGraph); if (!(type instanceof ArrayType)) { return panic("Tried to set items of non-array type"); } + type.setItems(items); this.registerType(type); } - modifyPropertiesIfNecessary(properties: ReadonlyMap): ReadonlyMap { + modifyPropertiesIfNecessary (properties: ReadonlyMap): ReadonlyMap { properties.forEach(p => this.assertTypeRefGraph(p.typeRef)); if (this.canonicalOrder) { properties = mapSortByKey(properties); } + if (this._allPropertiesOptional) { properties = mapMap(properties, cp => this.makeClassProperty(cp.typeRef, true)); } + return properties; } - getClassType( + getClassType ( attributes: TypeAttributes, properties: ReadonlyMap, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { properties = this.modifyPropertiesIfNecessary(properties); return this.getOrAddType( () => classTypeIdentity(attributes, properties), tr => new ClassType(tr, this.typeGraph, false, properties), attributes, - forwardingRef + forwardingRef, ); } // FIXME: Maybe just distinguish between this and `getClassType` // via a flag? That would make `ClassType.map` simpler. - getUniqueClassType( + getUniqueClassType ( attributes: TypeAttributes, isFixed: boolean, properties: ReadonlyMap | undefined, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { properties = definedMap(properties, p => this.modifyPropertiesIfNecessary(p)); return this.addType( forwardingRef, tref => new ClassType(tref, this.typeGraph, isFixed, properties), - attributes + attributes, ); } - getUnionType(attributes: TypeAttributes, members: ReadonlySet, forwardingRef?: TypeRef): TypeRef { + getUnionType (attributes: TypeAttributes, members: ReadonlySet, forwardingRef?: TypeRef): TypeRef { this.assertTypeRefSetGraph(members); return this.getOrAddType( () => unionTypeIdentity(attributes, members), tr => new UnionType(tr, this.typeGraph, members), attributes, - forwardingRef + forwardingRef, ); } // FIXME: why do we sometimes call this with defined members??? - getUniqueUnionType( + getUniqueUnionType ( attributes: TypeAttributes, members: ReadonlySet | undefined, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { this.assertTypeRefSetGraph(members); return this.addType(forwardingRef, tref => new UnionType(tref, this.typeGraph, members), attributes); } - getIntersectionType(attributes: TypeAttributes, members: ReadonlySet, forwardingRef?: TypeRef): TypeRef { + getIntersectionType (attributes: TypeAttributes, members: ReadonlySet, forwardingRef?: TypeRef): TypeRef { this.assertTypeRefSetGraph(members); return this.getOrAddType( () => intersectionTypeIdentity(attributes, members), tr => new IntersectionType(tr, this.typeGraph, members), attributes, - forwardingRef + forwardingRef, ); } // FIXME: why do we sometimes call this with defined members??? - getUniqueIntersectionType( + getUniqueIntersectionType ( attributes: TypeAttributes, members: ReadonlySet | undefined, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { this.assertTypeRefSetGraph(members); return this.addType(forwardingRef, tref => new IntersectionType(tref, this.typeGraph, members), attributes); } - setSetOperationMembers(ref: TypeRef, members: ReadonlySet): void { + setSetOperationMembers (ref: TypeRef, members: ReadonlySet): void { this.assertTypeRefSetGraph(members); const type = derefTypeRef(ref, this.typeGraph); if (!(type instanceof UnionType || type instanceof IntersectionType)) { return panic("Tried to set members of non-set-operation type"); } + type.setMembers(members); this.registerType(type); } - setLostTypeAttributes(): void { + setLostTypeAttributes (): void { return; } } diff --git a/packages/quicktype-core/src/TypeGraph.ts b/packages/quicktype-core/src/TypeGraph.ts index 09993039e..5ffa13a48 100644 --- a/packages/quicktype-core/src/TypeGraph.ts +++ b/packages/quicktype-core/src/TypeGraph.ts @@ -1,13 +1,18 @@ import { iterableFirst, setFilter, setUnionManyInto, setSubtract, mapMap, mapSome, setMap } from "collection-utils"; -import { Type, ClassType, UnionType, IntersectionType } from "./Type"; -import { separateNamedTypes, SeparatedNamedTypes, isNamedType, combineTypeAttributesOfTypes } from "./TypeUtils"; +import { type Type} from "./Type"; +import { ClassType, UnionType, IntersectionType } from "./Type"; +import { type SeparatedNamedTypes} from "./TypeUtils"; +import { separateNamedTypes, isNamedType, combineTypeAttributesOfTypes } from "./TypeUtils"; import { defined, assert, panic, mustNotHappen } from "./support/Support"; -import { TypeBuilder, StringTypeMapping, getNoStringTypeMapping, provenanceTypeAttributeKind } from "./TypeBuilder"; -import { GraphRewriteBuilder, GraphRemapBuilder, BaseGraphRewriteBuilder } from "./GraphRewriting"; +import { type TypeBuilder, type StringTypeMapping} from "./TypeBuilder"; +import { getNoStringTypeMapping, provenanceTypeAttributeKind } from "./TypeBuilder"; +import { type BaseGraphRewriteBuilder } from "./GraphRewriting"; +import { GraphRewriteBuilder, GraphRemapBuilder } from "./GraphRewriting"; import { TypeNames, namesTypeAttributeKind } from "./attributes/TypeNames"; import { Graph } from "./Graph"; -import { TypeAttributeKind, TypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +import { type TypeAttributeKind, type TypeAttributes} from "./attributes/TypeAttributes"; +import { emptyTypeAttributes } from "./attributes/TypeAttributes"; import { messageError } from "./Messages"; export type TypeRef = number; @@ -17,49 +22,49 @@ const indexMask = (1 << indexBits) - 1; const serialBits = 31 - indexBits; const serialMask = (1 << serialBits) - 1; -export function isTypeRef(x: any): x is TypeRef { +export function isTypeRef (x: any): x is TypeRef { return typeof x === "number"; } -export function makeTypeRef(graph: TypeGraph, index: number): TypeRef { +export function makeTypeRef (graph: TypeGraph, index: number): TypeRef { assert(index <= indexMask, "Too many types in graph"); - return ((graph.serial & serialMask) << indexBits) | index; + return (graph.serial & serialMask) << indexBits | index; } -export function typeRefIndex(tref: TypeRef): number { +export function typeRefIndex (tref: TypeRef): number { return tref & indexMask; } -export function assertTypeRefGraph(tref: TypeRef, graph: TypeGraph): void { +export function assertTypeRefGraph (tref: TypeRef, graph: TypeGraph): void { assert( - ((tref >> indexBits) & serialMask) === (graph.serial & serialMask), - "Mixing the wrong type reference and graph" + (tref >> indexBits & serialMask) === (graph.serial & serialMask), + "Mixing the wrong type reference and graph", ); } -function getGraph(graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): TypeGraph { +function getGraph (graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): TypeGraph { if (graphOrBuilder instanceof TypeGraph) return graphOrBuilder; return graphOrBuilder.originalGraph; } -export function derefTypeRef(tref: TypeRef, graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): Type { +export function derefTypeRef (tref: TypeRef, graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): Type { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); return graph.typeAtIndex(typeRefIndex(tref)); } -export function attributesForTypeRef( +export function attributesForTypeRef ( tref: TypeRef, - graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder + graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder, ): TypeAttributes { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); return graph.atIndex(typeRefIndex(tref))[1]; } -export function typeAndAttributesForTypeRef( +export function typeAndAttributesForTypeRef ( tref: TypeRef, - graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder + graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder, ): [Type, TypeAttributes] { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); @@ -69,28 +74,30 @@ export function typeAndAttributesForTypeRef( export class TypeAttributeStore { private readonly _topLevelValues: Map = new Map(); - constructor(private readonly _typeGraph: TypeGraph, private _values: (TypeAttributes | undefined)[]) {} + constructor (private readonly _typeGraph: TypeGraph, private _values: Array) {} - private getTypeIndex(t: Type): number { + private getTypeIndex (t: Type): number { const tref = t.typeRef; assertTypeRefGraph(tref, this._typeGraph); return typeRefIndex(tref); } - attributesForType(t: Type): TypeAttributes { + attributesForType (t: Type): TypeAttributes { const index = this.getTypeIndex(t); const maybeAttributes = this._values[index]; if (maybeAttributes !== undefined) { return maybeAttributes; } + return emptyTypeAttributes; } - attributesForTopLevel(name: string): TypeAttributes { + attributesForTopLevel (name: string): TypeAttributes { const maybeAttributes = this._topLevelValues.get(name); if (maybeAttributes !== undefined) { return maybeAttributes; } + return emptyTypeAttributes; } @@ -104,6 +111,7 @@ export class TypeAttributeStore { while (index >= this._values.length) { this._values.push(undefined); } + this._values[index] = this.setInMap(this.attributesForType(t), kind, value); } @@ -125,38 +133,39 @@ export class TypeAttributeStore { } export class TypeAttributeStoreView { - constructor( + constructor ( private readonly _attributeStore: TypeAttributeStore, - private readonly _definition: TypeAttributeKind + private readonly _definition: TypeAttributeKind, ) {} - set(t: Type, value: T): void { + set (t: Type, value: T): void { this._attributeStore.set(this._definition, t, value); } - setForTopLevel(name: string, value: T): void { + setForTopLevel (name: string, value: T): void { this._attributeStore.setForTopLevel(this._definition, name, value); } - tryGet(t: Type): T | undefined { + tryGet (t: Type): T | undefined { return this._attributeStore.tryGet(this._definition, t); } - get(t: Type): T { + get (t: Type): T { return defined(this.tryGet(t)); } - tryGetForTopLevel(name: string): T | undefined { + tryGetForTopLevel (name: string): T | undefined { return this._attributeStore.tryGetForTopLevel(this._definition, name); } - getForTopLevel(name: string): T { + getForTopLevel (name: string): T { return defined(this.tryGetForTopLevel(name)); } } export class TypeGraph { private _typeBuilder?: TypeBuilder; + private _attributeStore: TypeAttributeStore | undefined = undefined; // FIXME: OrderedMap? We lose the order in PureScript right now, though, @@ -165,30 +174,30 @@ export class TypeGraph { private _types?: Type[]; - private _parents: Set[] | undefined = undefined; + private _parents: Array> | undefined = undefined; private _printOnRewrite = false; - constructor( + constructor ( typeBuilder: TypeBuilder, readonly serial: number, - private readonly _haveProvenanceAttributes: boolean + private readonly _haveProvenanceAttributes: boolean, ) { this._typeBuilder = typeBuilder; } - private get isFrozen(): boolean { + private get isFrozen (): boolean { return this._typeBuilder === undefined; } - get attributeStore(): TypeAttributeStore { + get attributeStore (): TypeAttributeStore { return defined(this._attributeStore); } - freeze( + freeze ( topLevels: ReadonlyMap, types: Type[], - typeAttributes: (TypeAttributes | undefined)[] + typeAttributes: Array, ): void { assert(!this.isFrozen, "Tried to freeze TypeGraph a second time"); for (const t of types) { @@ -206,31 +215,33 @@ export class TypeGraph { this._topLevels = mapMap(topLevels, tref => derefTypeRef(tref, this)); } - get topLevels(): ReadonlyMap { + get topLevels (): ReadonlyMap { assert(this.isFrozen, "Cannot get top-levels from a non-frozen graph"); return this._topLevels; } - typeAtIndex(index: number): Type { + typeAtIndex (index: number): Type { if (this._typeBuilder !== undefined) { return this._typeBuilder.typeAtIndex(index); } + return defined(this._types)[index]; } - atIndex(index: number): [Type, TypeAttributes] { + atIndex (index: number): [Type, TypeAttributes] { if (this._typeBuilder !== undefined) { return this._typeBuilder.atIndex(index); } + const t = this.typeAtIndex(index); return [t, defined(this._attributeStore).attributesForType(t)]; } - private filterTypes(predicate: ((t: Type) => boolean) | undefined): ReadonlySet { + private filterTypes (predicate: ((t: Type) => boolean) | undefined): ReadonlySet { const seen = new Set(); let types: Type[] = []; - function addFromType(t: Type): void { + function addFromType (t: Type): void { if (seen.has(t)) return; seen.add(t); @@ -248,19 +259,20 @@ export class TypeGraph { for (const [, t] of this.topLevels) { addFromType(t); } + return new Set(types); } - allNamedTypes(): ReadonlySet { + allNamedTypes (): ReadonlySet { return this.filterTypes(isNamedType); } - allNamedTypesSeparated(): SeparatedNamedTypes { + allNamedTypesSeparated (): SeparatedNamedTypes { const types = this.allNamedTypes(); return separateNamedTypes(types); } - private allProvenance(): ReadonlySet { + private allProvenance (): ReadonlySet { assert(this._haveProvenanceAttributes); const view = new TypeAttributeStoreView(this.attributeStore, provenanceTypeAttributeKind); @@ -274,11 +286,11 @@ export class TypeGraph { return result; } - setPrintOnRewrite(): void { + setPrintOnRewrite (): void { this._printOnRewrite = true; } - private checkLostTypeAttributes(builder: BaseGraphRewriteBuilder, newGraph: TypeGraph): void { + private checkLostTypeAttributes (builder: BaseGraphRewriteBuilder, newGraph: TypeGraph): void { if (!this._haveProvenanceAttributes || builder.lostTypeAttributes) return; const oldProvenance = this.allProvenance(); @@ -290,7 +302,7 @@ export class TypeGraph { } } - private printRewrite(title: string): void { + private printRewrite (title: string): void { if (!this._printOnRewrite) return; console.log(`\n# ${title}`); @@ -309,7 +321,7 @@ export class TypeGraph { replacementGroups: T[][], debugPrintReconstitution: boolean, replacer: (typesToReplace: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef) => TypeRef, - force = false + force = false, ): TypeGraph { this.printRewrite(title); @@ -322,7 +334,7 @@ export class TypeGraph { this._haveProvenanceAttributes, replacementGroups, debugPrintReconstitution, - replacer + replacer, ); const newGraph = builder.finish(); @@ -338,13 +350,13 @@ export class TypeGraph { return removeIndirectionIntersections(newGraph, stringTypeMapping, debugPrintReconstitution); } - remap( + remap ( title: string, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, map: ReadonlyMap, debugPrintRemapping: boolean, - force = false + force = false, ): TypeGraph { this.printRewrite(title); @@ -356,7 +368,7 @@ export class TypeGraph { alphabetizeProperties, this._haveProvenanceAttributes, map, - debugPrintRemapping + debugPrintRemapping, ); const newGraph = builder.finish(); @@ -372,19 +384,19 @@ export class TypeGraph { return newGraph; } - garbageCollect(alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { + garbageCollect (alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { const newGraph = this.remap( "GC", getNoStringTypeMapping(), alphabetizeProperties, new Map(), debugPrintReconstitution, - true + true, ); return newGraph; } - rewriteFixedPoint(alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { + rewriteFixedPoint (alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { let graph: TypeGraph = this; for (;;) { const newGraph = this.rewrite( @@ -394,25 +406,26 @@ export class TypeGraph { [], debugPrintReconstitution, mustNotHappen, - true + true, ); if (graph.allTypesUnordered().size === newGraph.allTypesUnordered().size) { return graph; } + graph = newGraph; } } - allTypesUnordered(): ReadonlySet { + allTypesUnordered (): ReadonlySet { assert(this.isFrozen, "Tried to get all graph types before it was frozen"); return new Set(defined(this._types)); } - makeGraph(invertDirection: boolean, childrenOfType: (t: Type) => ReadonlySet): Graph { + makeGraph (invertDirection: boolean, childrenOfType: (t: Type) => ReadonlySet): Graph { return new Graph(defined(this._types), invertDirection, childrenOfType); } - getParentsOfType(t: Type): Set { + getParentsOfType (t: Type): Set { assertTypeRefGraph(t.typeRef, this); if (this._parents === undefined) { const parents = defined(this._types).map(_ => new Set()); @@ -422,12 +435,14 @@ export class TypeGraph { parents[index] = parents[index].add(p); } } + this._parents = parents; } + return this._parents[t.index]; } - printGraph(): void { + printGraph (): void { const types = defined(this._types); for (let i = 0; i < types.length; i++) { const t = types[i]; @@ -438,29 +453,32 @@ export class TypeGraph { parts.push( `children ${Array.from(children) .map(c => c.index) - .join(",")}` + .join(",")}`, ); } + for (const [kind, value] of t.getAttributes()) { const maybeString = kind.stringify(value); if (maybeString !== undefined) { parts.push(maybeString); } } + console.log(`${i}: ${parts.join(" | ")}`); } } } -export function noneToAny( +export function noneToAny ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { const noneTypes = setFilter(graph.allTypesUnordered(), t => t.kind === "none"); if (noneTypes.size === 0) { return graph; } + assert(noneTypes.size === 1, "Cannot have more than one none type"); return graph.rewrite( "none to any", @@ -472,16 +490,16 @@ export function noneToAny( const attributes = combineTypeAttributesOfTypes("union", types); const tref = builder.getPrimitiveType("any", attributes, forwardingRef); return tref; - } + }, ); } -export function optionalToNullable( +export function optionalToNullable ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { - function rewriteClass(c: ClassType, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { + function rewriteClass (c: ClassType, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { const properties = mapMap(c.getProperties(), (p, name) => { const t = p.type; let ref: TypeRef; @@ -495,11 +513,13 @@ export function optionalToNullable( } else { members = new Set([builder.reconstituteType(t), nullType]); } + const attributes = namesTypeAttributeKind.setDefaultInAttributes(t.getAttributes(), () => - TypeNames.make(new Set([name]), new Set(), true) + TypeNames.make(new Set([name]), new Set(), true), ); ref = builder.getUnionType(attributes, members); } + return builder.makeClassProperty(ref, p.isOptional); }); if (c.isFixed) { @@ -511,12 +531,13 @@ export function optionalToNullable( const classesWithOptional = setFilter( graph.allTypesUnordered(), - t => t instanceof ClassType && mapSome(t.getProperties(), p => p.isOptional) + t => t instanceof ClassType && mapSome(t.getProperties(), p => p.isOptional), ); const replacementGroups = Array.from(classesWithOptional).map(c => [c as ClassType]); if (classesWithOptional.size === 0) { return graph; } + return graph.rewrite( "optional to nullable", stringTypeMapping, @@ -527,16 +548,16 @@ export function optionalToNullable( assert(setOfClass.size === 1); const c = defined(iterableFirst(setOfClass)); return rewriteClass(c, builder, forwardingRef); - } + }, ); } -export function removeIndirectionIntersections( +export function removeIndirectionIntersections ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintRemapping: boolean + debugPrintRemapping: boolean, ): TypeGraph { - const map: [Type, Type][] = []; + const map: Array<[Type, Type]> = []; for (const t of graph.allTypesUnordered()) { if (!(t instanceof IntersectionType)) continue; @@ -548,10 +569,12 @@ export function removeIndirectionIntersections( map.push([t, member]); break; } + if (seen.has(member)) { // FIXME: Technically, this is an any type. return panic("There's a cycle of intersection types"); } + seen.add(member); current = member; } diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index 36fb166a9..f85767fef 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -2,51 +2,57 @@ import { setFilter, setSortBy, iterableFirst, setUnion, EqualityMap } from "coll import { defined, panic, assert, assertNever } from "./support/Support"; import { - TypeAttributes, + type TypeAttributes, + type CombinationKind, +} from "./attributes/TypeAttributes"; +import { combineTypeAttributes, emptyTypeAttributes, - CombinationKind } from "./attributes/TypeAttributes"; import { - Type, - PrimitiveType, + type Type, + type PrimitiveType, + type ClassProperty, + type SetOperationType} from "./Type"; +import { ArrayType, EnumType, ObjectType, MapType, ClassType, - ClassProperty, - SetOperationType, UnionType, - isPrimitiveStringTypeKind + isPrimitiveStringTypeKind, } from "./Type"; -import { stringTypesTypeAttributeKind, StringTypes } from "./attributes/StringTypes"; +import { type StringTypes } from "./attributes/StringTypes"; +import { stringTypesTypeAttributeKind } from "./attributes/StringTypes"; -export function assertIsObject(t: Type): ObjectType { +export function assertIsObject (t: Type): ObjectType { if (t instanceof ObjectType) { return t; } + return panic("Supposed object type is not an object type"); } -export function assertIsClass(t: Type): ClassType { +export function assertIsClass (t: Type): ClassType { if (!(t instanceof ClassType)) { return panic("Supposed class type is not a class type"); } + return t; } -export function setOperationMembersRecursively( +export function setOperationMembersRecursively ( setOperation: T, combinationKind: CombinationKind | undefined ): [ReadonlySet, TypeAttributes]; -export function setOperationMembersRecursively( +export function setOperationMembersRecursively ( setOperations: T[], combinationKind: CombinationKind | undefined ): [ReadonlySet, TypeAttributes]; -export function setOperationMembersRecursively( +export function setOperationMembersRecursively ( oneOrMany: T | T[], - combinationKind: CombinationKind | undefined + combinationKind: CombinationKind | undefined, ): [ReadonlySet, TypeAttributes] { const setOperations = Array.isArray(oneOrMany) ? oneOrMany : [oneOrMany]; const kind = setOperations[0].kind; @@ -55,7 +61,7 @@ export function setOperationMembersRecursively( const members = new Set(); let attributes = emptyTypeAttributes; - function process(t: Type): void { + function process (t: Type): void { if (t.kind === kind) { const so = t as T; if (processedSetOperations.has(so)) return; @@ -63,6 +69,7 @@ export function setOperationMembersRecursively( if (combinationKind !== undefined) { attributes = combineTypeAttributes(combinationKind, attributes, t.getAttributes()); } + for (const m of so.members) { process(m); } @@ -78,12 +85,13 @@ export function setOperationMembersRecursively( for (const so of setOperations) { process(so); } + return [members, attributes]; } -export function makeGroupsToFlatten( +export function makeGroupsToFlatten ( setOperations: Iterable, - include: ((members: ReadonlySet) => boolean) | undefined + include: ((members: ReadonlySet) => boolean) | undefined, ): Type[][] { const typeGroups = new EqualityMap, Set>(); for (const u of setOperations) { @@ -102,6 +110,7 @@ export function makeGroupsToFlatten( maybeSet.add(defined(iterableFirst(members))); } } + maybeSet.add(u); typeGroups.set(members, maybeSet); } @@ -109,25 +118,25 @@ export function makeGroupsToFlatten( return Array.from(typeGroups.values()).map(ts => Array.from(ts)); } -export function combineTypeAttributesOfTypes(combinationKind: CombinationKind, types: Iterable): TypeAttributes { +export function combineTypeAttributesOfTypes (combinationKind: CombinationKind, types: Iterable): TypeAttributes { return combineTypeAttributes( combinationKind, - Array.from(types).map(t => t.getAttributes()) + Array.from(types).map(t => t.getAttributes()), ); } -export function isAnyOrNull(t: Type): boolean { +export function isAnyOrNull (t: Type): boolean { return t.kind === "any" || t.kind === "null"; } // FIXME: We shouldn't have to sort here. This is just because we're not getting // back the right order from JSON Schema, due to the changes the intersection types // introduced. -export function removeNullFromUnion( +export function removeNullFromUnion ( t: UnionType, - sortBy: boolean | ((t: Type) => any) = false + sortBy: boolean | ((t: Type) => any) = false, ): [PrimitiveType | null, ReadonlySet] { - function sort(s: ReadonlySet): ReadonlySet { + function sort (s: ReadonlySet): ReadonlySet { if (sortBy === false) return s; if (sortBy === true) return setSortBy(s, m => m.kind); return setSortBy(s, sortBy); @@ -137,54 +146,58 @@ export function removeNullFromUnion( if (nullType === undefined) { return [null, sort(t.members)]; } + return [nullType as PrimitiveType, sort(setFilter(t.members, m => m.kind !== "null"))]; } -export function removeNullFromType(t: Type): [PrimitiveType | null, ReadonlySet] { +export function removeNullFromType (t: Type): [PrimitiveType | null, ReadonlySet] { if (t.kind === "null") { return [t as PrimitiveType, new Set()]; } + if (!(t instanceof UnionType)) { return [null, new Set([t])]; } + return removeNullFromUnion(t); } -export function nullableFromUnion(t: UnionType): Type | null { +export function nullableFromUnion (t: UnionType): Type | null { const [hasNull, nonNulls] = removeNullFromUnion(t); if (hasNull === null) return null; if (nonNulls.size !== 1) return null; return defined(iterableFirst(nonNulls)); } -export function nonNullTypeCases(t: Type): ReadonlySet { +export function nonNullTypeCases (t: Type): ReadonlySet { return removeNullFromType(t)[1]; } -export function getNullAsOptional(cp: ClassProperty): [boolean, ReadonlySet] { +export function getNullAsOptional (cp: ClassProperty): [boolean, ReadonlySet] { const [maybeNull, nonNulls] = removeNullFromType(cp.type); if (cp.isOptional) { return [true, nonNulls]; } + return [maybeNull !== null, nonNulls]; } // FIXME: Give this an appropriate name, considering that we don't distinguish // between named and non-named types anymore. -export function isNamedType(t: Type): boolean { - return ["class", "union", "enum", "object"].indexOf(t.kind) >= 0; +export function isNamedType (t: Type): boolean { + return ["class", "union", "enum", "object"].includes(t.kind); } -export type SeparatedNamedTypes = { - objects: ReadonlySet; +export interface SeparatedNamedTypes { enums: ReadonlySet; + objects: ReadonlySet; unions: ReadonlySet; -}; +} -export function separateNamedTypes(types: Iterable): SeparatedNamedTypes { +export function separateNamedTypes (types: Iterable): SeparatedNamedTypes { const objects = setFilter( types, - t => t.kind === "object" || t.kind === "class" + t => t.kind === "object" || t.kind === "class", ) as Set as ReadonlySet; const enums = setFilter(types, t => t instanceof EnumType) as Set as ReadonlySet; const unions = setFilter(types, t => t instanceof UnionType) as Set as ReadonlySet; @@ -192,42 +205,44 @@ export function separateNamedTypes(types: Iterable): SeparatedNamedTypes { return { objects, enums, unions }; } -export function directlyReachableTypes(t: Type, setForType: (t: Type) => ReadonlySet | null): ReadonlySet { +export function directlyReachableTypes (t: Type, setForType: (t: Type) => ReadonlySet | null): ReadonlySet { const set = setForType(t); if (set !== null) return set; return setUnion(...Array.from(t.getNonAttributeChildren()).map(c => directlyReachableTypes(c, setForType))); } -export function directlyReachableSingleNamedType(type: Type): Type | undefined { +export function directlyReachableSingleNamedType (type: Type): Type | undefined { const definedTypes = directlyReachableTypes(type, t => { if ( - (!(t instanceof UnionType) && isNamedType(t)) || - (t instanceof UnionType && nullableFromUnion(t) === null) + !(t instanceof UnionType) && isNamedType(t) || + t instanceof UnionType && nullableFromUnion(t) === null ) { return new Set([t]); } + return null; }); assert(definedTypes.size <= 1, "Cannot have more than one defined type per top-level"); return iterableFirst(definedTypes); } -export function stringTypesForType(t: PrimitiveType): StringTypes { +export function stringTypesForType (t: PrimitiveType): StringTypes { assert(t.kind === "string", "Only strings can have string types"); const stringTypes = stringTypesTypeAttributeKind.tryGetInAttributes(t.getAttributes()); if (stringTypes === undefined) { return panic("All strings must have a string type attribute"); } + return stringTypes; } -export type StringTypeMatchers = { +export interface StringTypeMatchers { + dateTimeType?: (dateTimeType: PrimitiveType) => U; dateType?: (dateType: PrimitiveType) => U; timeType?: (timeType: PrimitiveType) => U; - dateTimeType?: (dateTimeType: PrimitiveType) => U; -}; +} -export function matchTypeExhaustive( +export function matchTypeExhaustive ( t: Type, noneType: (noneType: PrimitiveType) => U, anyType: (anyType: PrimitiveType) => U, @@ -242,15 +257,17 @@ export function matchTypeExhaustive( objectType: (objectType: ObjectType) => U, enumType: (enumType: EnumType) => U, unionType: (unionType: UnionType) => U, - transformedStringType: (transformedStringType: PrimitiveType) => U + transformedStringType: (transformedStringType: PrimitiveType) => U, ): U { if (t.isPrimitive()) { if (isPrimitiveStringTypeKind(t.kind)) { if (t.kind === "string") { return stringType(t); } + return transformedStringType(t); } + const kind = t.kind; const f = { none: noneType, @@ -258,7 +275,7 @@ export function matchTypeExhaustive( null: nullType, bool: boolType, integer: integerType, - double: doubleType + double: doubleType, }[kind]; if (f !== undefined) return f(t); return assertNever(f); @@ -271,7 +288,7 @@ export function matchTypeExhaustive( return panic(`Unknown type ${t.kind}`); } -export function matchType( +export function matchType ( type: Type, anyType: (anyType: PrimitiveType) => U, nullType: (nullType: PrimitiveType) => U, @@ -284,9 +301,9 @@ export function matchType( mapType: (mapType: MapType) => U, enumType: (enumType: EnumType) => U, unionType: (unionType: UnionType) => U, - transformedStringType?: (transformedStringType: PrimitiveType) => U + transformedStringType?: (transformedStringType: PrimitiveType) => U, ): U { - function typeNotSupported(t: Type) { + function typeNotSupported (t: Type) { return panic(`Unsupported type ${t.kind} in non-exhaustive match`); } @@ -305,23 +322,23 @@ export function matchType( typeNotSupported, enumType, unionType, - transformedStringType || typeNotSupported + transformedStringType || typeNotSupported, ); } -export function matchCompoundType( +export function matchCompoundType ( t: Type, arrayType: (arrayType: ArrayType) => void, classType: (classType: ClassType) => void, mapType: (mapType: MapType) => void, objectType: (objectType: ObjectType) => void, - unionType: (unionType: UnionType) => void + unionType: (unionType: UnionType) => void, ): void { - function ignore(_: T): void { + function ignore (_: T): void { return; } - return matchTypeExhaustive( + matchTypeExhaustive( t, ignore, ignore, @@ -336,6 +353,6 @@ export function matchCompoundType( objectType, ignore, unionType, - ignore + ignore, ); } diff --git a/packages/quicktype-core/src/UnifyClasses.ts b/packages/quicktype-core/src/UnifyClasses.ts index cb445ae82..b94bec7ad 100644 --- a/packages/quicktype-core/src/UnifyClasses.ts +++ b/packages/quicktype-core/src/UnifyClasses.ts @@ -1,18 +1,21 @@ import { iterableFirst, setUnionInto } from "collection-utils"; -import { Type, ClassProperty, UnionType, ObjectType } from "./Type"; +import { type Type, type ClassProperty, type ObjectType } from "./Type"; +import { UnionType } from "./Type"; import { assertIsObject } from "./TypeUtils"; -import { TypeBuilder } from "./TypeBuilder"; -import { TypeLookerUp, GraphRewriteBuilder, BaseGraphRewriteBuilder } from "./GraphRewriting"; +import { type TypeBuilder } from "./TypeBuilder"; +import { type TypeLookerUp, type GraphRewriteBuilder, type BaseGraphRewriteBuilder } from "./GraphRewriting"; import { UnionBuilder, TypeRefUnionAccumulator } from "./UnionBuilder"; import { panic, assert, defined } from "./support/Support"; -import { TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; -import { TypeRef, derefTypeRef } from "./TypeGraph"; +import { type TypeAttributes} from "./attributes/TypeAttributes"; +import { combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +import { type TypeRef} from "./TypeGraph"; +import { derefTypeRef } from "./TypeGraph"; -function getCliqueProperties( +function getCliqueProperties ( clique: ObjectType[], builder: TypeBuilder, - makePropertyType: (types: ReadonlySet) => TypeRef + makePropertyType: (types: ReadonlySet) => TypeRef, ): [ReadonlyMap, TypeRef | undefined, boolean] { let lostTypeAttributes = false; let propertyNames = new Set(); @@ -28,6 +31,7 @@ function getCliqueProperties( if (additionalProperties === undefined) { additionalProperties = new Set(); } + if (additional !== undefined) { additionalProperties.add(additional); } @@ -45,6 +49,7 @@ function getCliqueProperties( if (maybeProperty.isOptional) { isOptional = true; } + types.add(maybeProperty.type); } @@ -63,10 +68,10 @@ function getCliqueProperties( return [unifiedProperties, unifiedAdditionalProperties, lostTypeAttributes]; } -function countProperties(clique: ObjectType[]): { - hasProperties: boolean; - hasAdditionalProperties: boolean; - hasNonAnyAdditionalProperties: boolean; +function countProperties (clique: ObjectType[]): { + hasAdditionalProperties: boolean, + hasNonAnyAdditionalProperties: boolean, + hasProperties: boolean, } { let hasProperties = false; let hasAdditionalProperties = false; @@ -75,6 +80,7 @@ function countProperties(clique: ObjectType[]): { if (o.getProperties().size > 0) { hasProperties = true; } + const additional = o.getAdditionalProperties(); if (additional !== undefined) { hasAdditionalProperties = true; @@ -83,29 +89,30 @@ function countProperties(clique: ObjectType[]): { } } } + return { hasProperties, hasAdditionalProperties, hasNonAnyAdditionalProperties }; } export class UnifyUnionBuilder extends UnionBuilder { - constructor( + constructor ( typeBuilder: BaseGraphRewriteBuilder, private readonly _makeObjectTypes: boolean, private readonly _makeClassesFixed: boolean, - private readonly _unifyTypes: (typesToUnify: TypeRef[]) => TypeRef + private readonly _unifyTypes: (typesToUnify: TypeRef[]) => TypeRef, ) { super(typeBuilder); } - protected makeObject( + protected makeObject ( objectRefs: TypeRef[], typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { const maybeTypeRef = this.typeBuilder.lookupTypeRefs(objectRefs, forwardingRef); if (maybeTypeRef !== undefined) { assert( forwardingRef === undefined || maybeTypeRef === forwardingRef, - "The forwarding ref must be consumed" + "The forwarding ref must be consumed", ); this.typeBuilder.addAttributes(maybeTypeRef, typeAttributes); return maybeTypeRef; @@ -118,18 +125,19 @@ export class UnifyUnionBuilder extends UnionBuilder assertIsObject(derefTypeRef(r, this.typeBuilder))); const { hasProperties, hasAdditionalProperties, hasNonAnyAdditionalProperties } = countProperties(objectTypes); - if (!this._makeObjectTypes && (hasNonAnyAdditionalProperties || (!hasProperties && hasAdditionalProperties))) { + if (!this._makeObjectTypes && (hasNonAnyAdditionalProperties || !hasProperties && hasAdditionalProperties)) { const propertyTypes = new Set(); for (const o of objectTypes) { setUnionInto( propertyTypes, - Array.from(o.getProperties().values()).map(cp => cp.typeRef) + Array.from(o.getProperties().values()).map(cp => cp.typeRef), ); } + const additionalPropertyTypes = new Set( objectTypes .filter(o => o.getAdditionalProperties() !== undefined) - .map(o => defined(o.getAdditionalProperties()).typeRef) + .map(o => defined(o.getAdditionalProperties()).typeRef), ); setUnionInto(propertyTypes, additionalPropertyTypes); return this.typeBuilder.getMapType(typeAttributes, this._unifyTypes(Array.from(propertyTypes))); @@ -140,17 +148,18 @@ export class UnifyUnionBuilder extends UnionBuilder { assert(types.size > 0, "Property has no type"); return this._unifyTypes(Array.from(types).map(t => t.typeRef)); - } + }, ); if (lostTypeAttributes) { this.typeBuilder.setLostTypeAttributes(); } + if (this._makeObjectTypes) { return this.typeBuilder.getUniqueObjectType( typeAttributes, properties, additionalProperties, - forwardingRef + forwardingRef, ); } else { assert(additionalProperties === undefined, "We have additional properties but want to make a class"); @@ -158,27 +167,27 @@ export class UnifyUnionBuilder extends UnionBuilder( +export function unionBuilderForUnification ( typeBuilder: GraphRewriteBuilder, makeObjectTypes: boolean, makeClassesFixed: boolean, - conflateNumbers: boolean + conflateNumbers: boolean, ): UnionBuilder { return new UnifyUnionBuilder(typeBuilder, makeObjectTypes, makeClassesFixed, trefs => unifyTypes( @@ -186,20 +195,20 @@ export function unionBuilderForUnification( emptyTypeAttributes, typeBuilder, unionBuilderForUnification(typeBuilder, makeObjectTypes, makeClassesFixed, conflateNumbers), - conflateNumbers - ) + conflateNumbers, + ), ); } // typeAttributes must not be reconstituted yet. // FIXME: The UnionBuilder might end up not being used. -export function unifyTypes( +export function unifyTypes ( types: ReadonlySet, typeAttributes: TypeAttributes, typeBuilder: GraphRewriteBuilder, unionBuilder: UnionBuilder, conflateNumbers: boolean, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef { typeAttributes = typeBuilder.reconstituteTypeAttributes(typeAttributes); if (types.size === 0) { diff --git a/packages/quicktype-core/src/UnionBuilder.ts b/packages/quicktype-core/src/UnionBuilder.ts index c4a21d9d8..e3840144a 100644 --- a/packages/quicktype-core/src/UnionBuilder.ts +++ b/packages/quicktype-core/src/UnionBuilder.ts @@ -1,18 +1,20 @@ import { mapMerge, mapUpdateInto, mapMap, setUnionInto } from "collection-utils"; -import { TypeKind, PrimitiveStringTypeKind, Type, UnionType, PrimitiveTypeKind, isPrimitiveTypeKind } from "./Type"; +import { type TypeKind, type PrimitiveStringTypeKind, type Type, type PrimitiveTypeKind} from "./Type"; +import { UnionType, isPrimitiveTypeKind } from "./Type"; import { matchTypeExhaustive } from "./TypeUtils"; import { - TypeAttributes, + type TypeAttributes} from "./attributes/TypeAttributes"; +import { combineTypeAttributes, emptyTypeAttributes, makeTypeAttributesInferred, - increaseTypeAttributesDistance + increaseTypeAttributesDistance, } from "./attributes/TypeAttributes"; import { defined, assert, panic, assertNever } from "./support/Support"; -import { TypeBuilder } from "./TypeBuilder"; +import { type TypeBuilder } from "./TypeBuilder"; import { StringTypes, stringTypesTypeAttributeKind } from "./attributes/StringTypes"; -import { TypeRef } from "./TypeGraph"; +import { type TypeRef } from "./TypeGraph"; // FIXME: This interface is badly designed. All the properties // should use immutable types, and getMemberKinds should be @@ -22,53 +24,54 @@ import { TypeRef } from "./TypeGraph"; // Well, maybe getMemberKinds() is fine as it is. export interface UnionTypeProvider { readonly arrayData: TArrayData; - readonly objectData: TObjectData; - readonly enumCases: ReadonlySet; - getMemberKinds(): TypeAttributeMap; + getMemberKinds: () => TypeAttributeMap; readonly lostTypeAttributes: boolean; + + readonly objectData: TObjectData; } export type TypeAttributeMap = Map; type TypeAttributeMapBuilder = Map; -function addAttributes( +function addAttributes ( accumulatorAttributes: TypeAttributes | undefined, - newAttributes: TypeAttributes + newAttributes: TypeAttributes, ): TypeAttributes { if (accumulatorAttributes === undefined) return newAttributes; return combineTypeAttributes("union", accumulatorAttributes, newAttributes); } -function setAttributes( +function setAttributes ( attributeMap: TypeAttributeMap, kind: T, - newAttributes: TypeAttributes + newAttributes: TypeAttributes, ): void { attributeMap.set(kind, addAttributes(attributeMap.get(kind), newAttributes)); } -function addAttributesToBuilder( +function addAttributesToBuilder ( builder: TypeAttributeMapBuilder, kind: T, - newAttributes: TypeAttributes + newAttributes: TypeAttributes, ): void { let arr = builder.get(kind); if (arr === undefined) { arr = []; builder.set(kind, arr); } + arr.push(newAttributes); } -function buildTypeAttributeMap(builder: TypeAttributeMapBuilder): TypeAttributeMap { +function buildTypeAttributeMap (builder: TypeAttributeMapBuilder): TypeAttributeMap { return mapMap(builder, arr => combineTypeAttributes("union", arr)); } -function moveAttributes(map: TypeAttributeMap, fromKind: T, toKind: T): void { +function moveAttributes (map: TypeAttributeMap, fromKind: T, toKind: T): void { const fromAttributes = defined(map.get(fromKind)); map.delete(fromKind); setAttributes(map, toKind, fromAttributes); @@ -76,45 +79,50 @@ function moveAttributes(map: TypeAttributeMap, fromKind: export class UnionAccumulator implements UnionTypeProvider { private readonly _nonStringTypeAttributes: TypeAttributeMapBuilder = new Map(); + private readonly _stringTypeAttributes: TypeAttributeMapBuilder = new Map(); readonly arrayData: TArray[] = []; + readonly objectData: TObject[] = []; private readonly _enumCases: Set = new Set(); private _lostTypeAttributes = false; - constructor(private readonly _conflateNumbers: boolean) {} + constructor (private readonly _conflateNumbers: boolean) {} - private have(kind: TypeKind): boolean { + private have (kind: TypeKind): boolean { return ( this._nonStringTypeAttributes.has(kind) || this._stringTypeAttributes.has(kind as PrimitiveStringTypeKind) ); } - addNone(_attributes: TypeAttributes): void { + addNone (_attributes: TypeAttributes): void { // FIXME: Add them to all members? Or add them to the union, which means we'd have // to change getMemberKinds() to also return the attributes for the union itself, // or add a new method that does that. this._lostTypeAttributes = true; } - addAny(attributes: TypeAttributes): void { + + addAny (attributes: TypeAttributes): void { addAttributesToBuilder(this._nonStringTypeAttributes, "any", attributes); this._lostTypeAttributes = true; } - addPrimitive(kind: PrimitiveTypeKind, attributes: TypeAttributes): void { + + addPrimitive (kind: PrimitiveTypeKind, attributes: TypeAttributes): void { assert(kind !== "any", "any must be added with addAny"); addAttributesToBuilder(this._nonStringTypeAttributes, kind, attributes); } - protected addFullStringType(attributes: TypeAttributes, stringTypes: StringTypes | undefined): void { + protected addFullStringType (attributes: TypeAttributes, stringTypes: StringTypes | undefined): void { let stringTypesAttributes: TypeAttributes | undefined = undefined; if (stringTypes === undefined) { stringTypes = stringTypesTypeAttributeKind.tryGetInAttributes(attributes); } else { stringTypesAttributes = stringTypesTypeAttributeKind.makeAttributes(stringTypes); } + if (stringTypes === undefined) { stringTypes = StringTypes.unrestricted; stringTypesAttributes = stringTypesTypeAttributeKind.makeAttributes(stringTypes); @@ -124,7 +132,7 @@ export class UnionAccumulator implements UnionTypeProvider implements UnionTypeProvider, attributes: TypeAttributes): void { + addEnum (cases: ReadonlySet, attributes: TypeAttributes): void { const maybeStringAttributes = this._stringTypeAttributes.get("string"); if (maybeStringAttributes !== undefined) { addAttributesToBuilder(this._stringTypeAttributes, "string", attributes); return; } + addAttributesToBuilder(this._nonStringTypeAttributes, "enum", attributes); setUnionInto(this._enumCases, cases); } - addStringCases(cases: string[], attributes: TypeAttributes): void { + addStringCases (cases: string[], attributes: TypeAttributes): void { this.addFullStringType(attributes, StringTypes.fromCases(cases)); } - addStringCase(s: string, count: number, attributes: TypeAttributes): void { + + addStringCase (s: string, count: number, attributes: TypeAttributes): void { this.addFullStringType(attributes, StringTypes.fromCase(s, count)); } - get enumCases(): ReadonlySet { + get enumCases (): ReadonlySet { return this._enumCases; } - getMemberKinds(): TypeAttributeMap { + getMemberKinds (): TypeAttributeMap { assert(!(this.have("enum") && this.have("string")), "We can't have both strings and enums in the same union"); let merged = mapMerge( buildTypeAttributeMap(this._nonStringTypeAttributes), - buildTypeAttributeMap(this._stringTypeAttributes) + buildTypeAttributeMap(this._stringTypeAttributes), ); if (merged.size === 0) { @@ -201,26 +213,28 @@ export class UnionAccumulator implements UnionTypeProvider): [ReadonlyMap, TypeAttributes] { +function attributesForTypes (types: Iterable): [ReadonlyMap, TypeAttributes] { // These two maps are the reverse of each other. unionsForType is all the unions // that are ancestors of that type, when going from one of the given types, only // following unions. @@ -232,7 +246,7 @@ function attributesForTypes(types: Iterable): [ReadonlyMap = new Set(); - function traverse(t: Type, path: UnionOrFaux[], isEquivalentToRoot: boolean): void { + function traverse (t: Type, path: UnionOrFaux[], isEquivalentToRoot: boolean): void { if (t instanceof UnionType) { unions.add(t); if (isEquivalentToRoot) { @@ -244,11 +258,12 @@ function attributesForTypes(types: Iterable): [ReadonlyMap (s === undefined ? new Set(path) : setUnionInto(s, path))); + mapUpdateInto(unionsForType, t, s => s === undefined ? new Set(path) : setUnionInto(s, path)); for (const u of path) { - mapUpdateInto(typesForUnion, u, s => (s === undefined ? new Set([t]) : s.add(t))); + mapUpdateInto(typesForUnion, u, s => s === undefined ? new Set([t]) : s.add(t)); } } } @@ -263,7 +278,7 @@ function attributesForTypes(types: Iterable): [ReadonlyMap defined(typesForUnion.get(u)).size === 1); assert( singleAncestors.every(u => defined(typesForUnion.get(u)).has(t)), - "We messed up bookkeeping" + "We messed up bookkeeping", ); const inheritedAttributes = singleAncestors.map(u => u.getAttributes()); return combineTypeAttributes("union", [t.getAttributes()].concat(inheritedAttributes)); @@ -273,10 +288,12 @@ function attributesForTypes(types: Iterable): [ReadonlyMap): [ReadonlyMap { // There is a method analogous to this in the IntersectionAccumulator. It might // make sense to find a common interface. - private addType(t: Type, attributes: TypeAttributes): void { + private addType (t: Type, attributes: TypeAttributes): void { matchTypeExhaustive( t, _noneType => this.addNone(attributes), @@ -308,38 +325,39 @@ export class TypeRefUnionAccumulator extends UnionAccumulator return panic("The unions should have been eliminated in attributesForTypesInUnion"); }, transformedStringType => - this.addStringType(transformedStringType.kind as PrimitiveStringTypeKind, attributes) + this.addStringType(transformedStringType.kind as PrimitiveStringTypeKind, attributes), ); } - addTypes(types: Iterable): TypeAttributes { + addTypes (types: Iterable): TypeAttributes { const [attributesMap, unionAttributes] = attributesForTypes(types); for (const [t, attributes] of attributesMap) { this.addType(t, attributes); } + return unionAttributes; } } export abstract class UnionBuilder { - constructor(protected readonly typeBuilder: TBuilder) {} + constructor (protected readonly typeBuilder: TBuilder) {} - protected abstract makeObject( + protected abstract makeObject ( objects: TObjectData, typeAttributes: TypeAttributes, forwardingRef: TypeRef | undefined ): TypeRef; - protected abstract makeArray( + protected abstract makeArray ( arrays: TArrayData, typeAttributes: TypeAttributes, forwardingRef: TypeRef | undefined ): TypeRef; - private makeTypeOfKind( + private makeTypeOfKind ( typeProvider: UnionTypeProvider, kind: TypeKind, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { switch (kind) { case "string": @@ -354,18 +372,20 @@ export abstract class UnionBuilder, unique: boolean, typeAttributes: TypeAttributes, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { const kinds = typeProvider.getMemberKinds(); @@ -382,7 +402,7 @@ export abstract class UnionBuilder; export type AccessorNames = Map; class AccessorNamesTypeAttributeKind extends TypeAttributeKind { - constructor() { + constructor () { super("accessorNames"); } - makeInferred(_: AccessorNames): undefined { + makeInferred (_: AccessorNames): undefined { return undefined; } } @@ -31,7 +32,7 @@ class AccessorNamesTypeAttributeKind extends TypeAttributeKind { export const accessorNamesTypeAttributeKind: TypeAttributeKind = new AccessorNamesTypeAttributeKind(); // Returns [name, isFixed]. -function getFromEntry(entry: AccessorEntry, language: string): [string, boolean] | undefined { +function getFromEntry (entry: AccessorEntry, language: string): [string, boolean] | undefined { if (typeof entry === "string") return [entry, false]; const maybeForLanguage = entry.get(language); @@ -43,28 +44,28 @@ function getFromEntry(entry: AccessorEntry, language: string): [string, boolean] return undefined; } -export function lookupKey(accessors: AccessorNames, key: string, language: string): [string, boolean] | undefined { +export function lookupKey (accessors: AccessorNames, key: string, language: string): [string, boolean] | undefined { const entry = accessors.get(key); if (entry === undefined) return undefined; return getFromEntry(entry, language); } -export function objectPropertyNames(o: ObjectType, language: string): Map { +export function objectPropertyNames (o: ObjectType, language: string): Map { const accessors = accessorNamesTypeAttributeKind.tryGetInAttributes(o.getAttributes()); const map = o.getProperties(); if (accessors === undefined) return mapMap(map, _ => undefined); return mapMap(map, (_cp, n) => lookupKey(accessors, n, language)); } -export function enumCaseNames(e: EnumType, language: string): Map { +export function enumCaseNames (e: EnumType, language: string): Map { const accessors = accessorNamesTypeAttributeKind.tryGetInAttributes(e.getAttributes()); if (accessors === undefined) return mapMap(e.cases.entries(), _ => undefined); return mapMap(e.cases.entries(), c => lookupKey(accessors, c, language)); } -export function getAccessorName( +export function getAccessorName ( names: Map, - original: string + original: string, ): [string | undefined, boolean] { const maybeName = names.get(original); if (maybeName === undefined) return [undefined, false]; @@ -79,15 +80,15 @@ export function getAccessorName( // up its union's identifier(s), and then look up the member's accessor entries for that // identifier. Of course we might find more than one, potentially conflicting. class UnionIdentifierTypeAttributeKind extends TypeAttributeKind> { - constructor() { + constructor () { super("unionIdentifier"); } - combine(arr: ReadonlySet[]): ReadonlySet { + combine (arr: Array>): ReadonlySet { return setUnionManyInto(new Set(), arr); } - makeInferred(_: ReadonlySet): ReadonlySet { + makeInferred (_: ReadonlySet): ReadonlySet { return new Set(); } } @@ -97,22 +98,23 @@ export const unionIdentifierTypeAttributeKind: TypeAttributeKind> { - constructor() { + constructor () { super("unionMemberNames"); } - combine(arr: Map[]): Map { + combine (arr: Array>): Map { const result = new Map(); for (const m of arr) { mapMergeInto(result, m); } + return result; } } @@ -120,13 +122,13 @@ class UnionMemberNamesTypeAttributeKind extends TypeAttributeKind> = new UnionMemberNamesTypeAttributeKind(); -export function makeUnionMemberNamesAttribute(unionAttributes: TypeAttributes, entry: AccessorEntry): TypeAttributes { +export function makeUnionMemberNamesAttribute (unionAttributes: TypeAttributes, entry: AccessorEntry): TypeAttributes { const identifiers = defined(unionIdentifierTypeAttributeKind.tryGetInAttributes(unionAttributes)); const map = mapFromIterable(identifiers, _ => entry); return unionMemberNamesTypeAttributeKind.makeAttributes(map); } -export function unionMemberName(u: UnionType, member: Type, language: string): [string | undefined, boolean] { +export function unionMemberName (u: UnionType, member: Type, language: string): [string | undefined, boolean] { const identifiers = unionIdentifierTypeAttributeKind.tryGetInAttributes(u.getAttributes()); if (identifiers === undefined) return [undefined, false]; @@ -166,29 +168,30 @@ export function unionMemberName(u: UnionType, member: Type, language: string): [ return [first, isFixed]; } -function isAccessorEntry(x: any): x is string | { [language: string]: string } { +function isAccessorEntry (x: any): x is string | { [language: string]: string, } { if (typeof x === "string") { return true; } + return isStringMap(x, (v: any): v is string => typeof v === "string"); } -function makeAccessorEntry(ae: string | { [language: string]: string }): AccessorEntry { +function makeAccessorEntry (ae: string | { [language: string]: string, }): AccessorEntry { if (typeof ae === "string") return ae; return mapFromObject(ae); } -export function makeAccessorNames(x: any): AccessorNames { +export function makeAccessorNames (x: any): AccessorNames { // FIXME: Do proper error reporting const stringMap = checkStringMap(x, isAccessorEntry); return mapMap(mapFromObject(stringMap), makeAccessorEntry); } -export function accessorNamesAttributeProducer( +export function accessorNamesAttributeProducer ( schema: JSONSchema, canonicalRef: Ref, _types: Set, - cases: JSONSchema[] | undefined + cases: JSONSchema[] | undefined, ): JSONSchemaAttributes | undefined { if (typeof schema !== "object") return undefined; const maybeAccessors = schema["qt-accessors"]; @@ -202,10 +205,10 @@ export function accessorNamesAttributeProducer( const accessors = checkArray(maybeAccessors, isAccessorEntry); messageAssert(cases.length === accessors.length, "SchemaWrongAccessorEntryArrayLength", { operation: "oneOf", - ref: canonicalRef.push("oneOf") + ref: canonicalRef.push("oneOf"), }); const caseAttributes = accessors.map(accessor => - makeUnionMemberNamesAttribute(identifierAttribute, makeAccessorEntry(accessor)) + makeUnionMemberNamesAttribute(identifierAttribute, makeAccessorEntry(accessor)), ); return { forUnion: identifierAttribute, forCases: caseAttributes }; } diff --git a/packages/quicktype-core/src/attributes/Constraints.ts b/packages/quicktype-core/src/attributes/Constraints.ts index a0370f4cc..d63442f26 100644 --- a/packages/quicktype-core/src/attributes/Constraints.ts +++ b/packages/quicktype-core/src/attributes/Constraints.ts @@ -1,41 +1,43 @@ -import { Type, TypeKind } from "../Type"; +import { type Type, type TypeKind } from "../Type"; import { TypeAttributeKind } from "./TypeAttributes"; import { assert } from "../support/Support"; import { messageError } from "../Messages"; -import { JSONSchemaType, JSONSchemaAttributes, Ref } from "../input/JSONSchemaInput"; -import { JSONSchema } from "../input/JSONSchemaStore"; +import { type JSONSchemaType, type JSONSchemaAttributes, type Ref } from "../input/JSONSchemaInput"; +import { type JSONSchema } from "../input/JSONSchemaStore"; // This can't be an object type, unfortunately, because it's in the // type's identity and as such must be comparable and hashable with // `areEqual`, `hashCodeOf`. export type MinMaxConstraint = [number | undefined, number | undefined]; -function checkMinMaxConstraint(minmax: MinMaxConstraint): MinMaxConstraint | undefined { +function checkMinMaxConstraint (minmax: MinMaxConstraint): MinMaxConstraint | undefined { const [min, max] = minmax; if (typeof min === "number" && typeof max === "number" && min > max) { return messageError("MiscInvalidMinMaxConstraint", { min, max }); } + if (min === undefined && max === undefined) { return undefined; } + return minmax; } export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind { - constructor( + constructor ( name: string, - private _typeKinds: Set, + private readonly _typeKinds: Set, private _minSchemaProperty: string, - private _maxSchemaProperty: string + private _maxSchemaProperty: string, ) { super(name); } - get inIdentity(): boolean { + get inIdentity (): boolean { return true; } - combine(arr: MinMaxConstraint[]): MinMaxConstraint | undefined { + combine (arr: MinMaxConstraint[]): MinMaxConstraint | undefined { assert(arr.length > 0); let [min, max] = arr[0]; @@ -46,16 +48,18 @@ export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind 0); let [min, max] = arr[0]; @@ -66,32 +70,35 @@ export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind = new "minMax", new Set(["integer", "double"]), "minimum", - "maximum" + "maximum", ); export const minMaxLengthTypeAttributeKind: TypeAttributeKind = new MinMaxConstraintTypeAttributeKind( "minMaxLength", new Set(["string"]), "minLength", - "maxLength" + "maxLength", ); -function producer(schema: JSONSchema, minProperty: string, maxProperty: string): MinMaxConstraint | undefined { +function producer (schema: JSONSchema, minProperty: string, maxProperty: string): MinMaxConstraint | undefined { if (!(typeof schema === "object")) return undefined; let min: number | undefined = undefined; @@ -119,6 +126,7 @@ function producer(schema: JSONSchema, minProperty: string, maxProperty: string): if (typeof schema[minProperty] === "number") { min = schema[minProperty]; } + if (typeof schema[maxProperty] === "number") { max = schema[maxProperty]; } @@ -127,10 +135,10 @@ function producer(schema: JSONSchema, minProperty: string, maxProperty: string): return [min, max]; } -export function minMaxAttributeProducer( +export function minMaxAttributeProducer ( schema: JSONSchema, _ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!types.has("number") && !types.has("integer")) return undefined; @@ -139,10 +147,10 @@ export function minMaxAttributeProducer( return { forNumber: minMaxTypeAttributeKind.makeAttributes(maybeMinMax) }; } -export function minMaxLengthAttributeProducer( +export function minMaxLengthAttributeProducer ( schema: JSONSchema, _ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!types.has("string")) return undefined; @@ -151,38 +159,38 @@ export function minMaxLengthAttributeProducer( return { forString: minMaxLengthTypeAttributeKind.makeAttributes(maybeMinMaxLength) }; } -export function minMaxValueForType(t: Type): MinMaxConstraint | undefined { +export function minMaxValueForType (t: Type): MinMaxConstraint | undefined { return minMaxTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } -export function minMaxLengthForType(t: Type): MinMaxConstraint | undefined { +export function minMaxLengthForType (t: Type): MinMaxConstraint | undefined { return minMaxLengthTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } export class PatternTypeAttributeKind extends TypeAttributeKind { - constructor() { + constructor () { super("pattern"); } - get inIdentity(): boolean { + get inIdentity (): boolean { return true; } - combine(arr: string[]): string { + combine (arr: string[]): string { assert(arr.length > 0); return arr.map(p => `(${p})`).join("|"); } - intersect(_arr: string[]): string | undefined { + intersect (_arr: string[]): string | undefined { /** FIXME!!! what is the intersection of regexps? */ return undefined; } - makeInferred(_: string): undefined { + makeInferred (_: string): undefined { return undefined; } - addToSchema(schema: { [name: string]: unknown }, t: Type, attr: string): void { + addToSchema (schema: { [name: string]: unknown, }, t: Type, attr: string): void { if (t.kind !== "string") return; schema.pattern = attr; } @@ -190,10 +198,10 @@ export class PatternTypeAttributeKind extends TypeAttributeKind { export const patternTypeAttributeKind: TypeAttributeKind = new PatternTypeAttributeKind(); -export function patternAttributeProducer( +export function patternAttributeProducer ( schema: JSONSchema, _ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!(typeof schema === "object")) return undefined; if (!types.has("string")) return undefined; @@ -203,6 +211,6 @@ export function patternAttributeProducer( return { forString: patternTypeAttributeKind.makeAttributes(patt) }; } -export function patternForType(t: Type): string | undefined { +export function patternForType (t: Type): string | undefined { return patternTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } diff --git a/packages/quicktype-core/src/attributes/Description.ts b/packages/quicktype-core/src/attributes/Description.ts index 6684b95c3..34bc6151c 100644 --- a/packages/quicktype-core/src/attributes/Description.ts +++ b/packages/quicktype-core/src/attributes/Description.ts @@ -5,51 +5,54 @@ import { iterableFirst, setUnionManyInto, mapMergeWithInto, - setSubtract + setSubtract, } from "collection-utils"; // There's a cyclic import here. Ignoring now because it requires a large refactor. // skipcq: JS-E1008 import { TypeAttributeKind, emptyTypeAttributes } from "./TypeAttributes"; // FIXME: This is a circular import -import { JSONSchemaType, Ref, JSONSchemaAttributes, PathElementKind, PathElement } from "../input/JSONSchemaInput"; -import { JSONSchema } from "../input/JSONSchemaStore"; -import { Type } from "../Type"; - -export function addDescriptionToSchema( - schema: { [name: string]: unknown }, - description: Iterable | undefined +import { type JSONSchemaType, type Ref, type JSONSchemaAttributes, type PathElement } from "../input/JSONSchemaInput"; +import { PathElementKind } from "../input/JSONSchemaInput"; +import { type JSONSchema } from "../input/JSONSchemaStore"; +import { type Type } from "../Type"; + +export function addDescriptionToSchema ( + schema: { [name: string]: unknown, }, + description: Iterable | undefined, ): void { if (description === undefined) return; schema.description = Array.from(description).join("\n"); } class DescriptionTypeAttributeKind extends TypeAttributeKind> { - constructor() { + constructor () { super("description"); } - combine(attrs: ReadonlySet[]): ReadonlySet { + combine (attrs: Array>): ReadonlySet { return setUnionManyInto(new Set(), attrs); } - makeInferred(_: ReadonlySet): undefined { + makeInferred (_: ReadonlySet): undefined { return undefined; } - addToSchema(schema: { [name: string]: unknown }, _t: Type, attrs: ReadonlySet): void { + addToSchema (schema: { [name: string]: unknown, }, _t: Type, attrs: ReadonlySet): void { addDescriptionToSchema(schema, attrs); } - stringify(descriptions: ReadonlySet): string | undefined { + stringify (descriptions: ReadonlySet): string | undefined { let result = iterableFirst(descriptions); if (result === undefined) return undefined; if (result.length > 5 + 3) { result = `${result.slice(0, 5)}...`; } + if (descriptions.size > 1) { result = `${result}, ...`; } + return result; } } @@ -57,24 +60,25 @@ class DescriptionTypeAttributeKind extends TypeAttributeKind export const descriptionTypeAttributeKind: TypeAttributeKind> = new DescriptionTypeAttributeKind(); class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind>> { - constructor() { + constructor () { super("propertyDescriptions"); } - combine(attrs: Map>[]): Map> { + combine (attrs: Array>>): Map> { // FIXME: Implement this with mutable sets const result = new Map>(); for (const attr of attrs) { mapMergeWithInto(result, (sa, sb) => setUnion(sa, sb), attr); } + return result; } - makeInferred(_: Map>): undefined { + makeInferred (_: Map>): undefined { return undefined; } - stringify(propertyDescriptions: Map>): string | undefined { + stringify (propertyDescriptions: Map>): string | undefined { if (propertyDescriptions.size === 0) return undefined; return `prop descs: ${propertyDescriptions.size}`; } @@ -83,14 +87,14 @@ class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind>> = new PropertyDescriptionsTypeAttributeKind(); -function isPropertiesKey(el: PathElement): boolean { +function isPropertiesKey (el: PathElement): boolean { return el.kind === PathElementKind.KeyOrIndex && el.key === "properties"; } -export function descriptionAttributeProducer( +export function descriptionAttributeProducer ( schema: JSONSchema, ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!(typeof schema === "object")) return undefined; @@ -119,6 +123,7 @@ export function descriptionAttributeProducer( return new Set([desc]); } } + return undefined; }); if (propertyDescriptions.size > 0) { diff --git a/packages/quicktype-core/src/attributes/EnumValues.ts b/packages/quicktype-core/src/attributes/EnumValues.ts index f81b73a37..ccb3a6a24 100644 --- a/packages/quicktype-core/src/attributes/EnumValues.ts +++ b/packages/quicktype-core/src/attributes/EnumValues.ts @@ -1,32 +1,34 @@ import { mapMap } from "collection-utils"; -import { lookupKey, AccessorNames, makeAccessorNames } from "./AccessorNames"; -import { EnumType } from "../Type"; +import { type AccessorNames} from "./AccessorNames"; +import { lookupKey, makeAccessorNames } from "./AccessorNames"; +import { type EnumType } from "../Type"; import { TypeAttributeKind } from "./TypeAttributes"; -import { JSONSchema } from "../input/JSONSchemaStore"; -import { Ref, JSONSchemaType, JSONSchemaAttributes } from "../input/JSONSchemaInput"; +import { type JSONSchema } from "../input/JSONSchemaStore"; +import { type Ref, type JSONSchemaType, type JSONSchemaAttributes } from "../input/JSONSchemaInput"; class EnumValuesTypeAttributeKind extends TypeAttributeKind { - constructor() { + constructor () { super("enumValues"); } - makeInferred(_: AccessorNames) { + + makeInferred (_: AccessorNames) { return undefined; } } export const enumValuesTypeAttributeKind: TypeAttributeKind = new EnumValuesTypeAttributeKind(); -export function enumCaseValues(e: EnumType, language: string): Map { +export function enumCaseValues (e: EnumType, language: string): Map { const enumValues = enumValuesTypeAttributeKind.tryGetInAttributes(e.getAttributes()); if (enumValues === undefined) return mapMap(e.cases.entries(), _ => undefined); return mapMap(e.cases.entries(), c => lookupKey(enumValues, c, language)); } -export function enumValuesAttributeProducer( +export function enumValuesAttributeProducer ( schema: JSONSchema, _canonicalRef: Ref | undefined, - _types: Set + _types: Set, ): JSONSchemaAttributes | undefined { if (typeof schema !== "object") return undefined; diff --git a/packages/quicktype-core/src/attributes/StringTypes.ts b/packages/quicktype-core/src/attributes/StringTypes.ts index c14d7d58d..555301d80 100644 --- a/packages/quicktype-core/src/attributes/StringTypes.ts +++ b/packages/quicktype-core/src/attributes/StringTypes.ts @@ -7,47 +7,49 @@ import { mapMergeWithInto, definedMap, addHashCode, - setUnionInto + setUnionInto, } from "collection-utils"; import { TypeAttributeKind } from "./TypeAttributes"; import { defined, assert } from "../support/Support"; -import { StringTypeMapping, stringTypeMappingGet } from "../TypeBuilder"; -import { TransformedStringTypeKind } from "../Type"; -import { DateTimeRecognizer } from "../DateTime"; +import { type StringTypeMapping} from "../TypeBuilder"; +import { stringTypeMappingGet } from "../TypeBuilder"; +import { type TransformedStringTypeKind } from "../Type"; +import { type DateTimeRecognizer } from "../DateTime"; export class StringTypes { static readonly unrestricted: StringTypes = new StringTypes(undefined, new Set()); - static fromCase(s: string, count: number): StringTypes { - const caseMap: { [name: string]: number } = {}; + static fromCase (s: string, count: number): StringTypes { + const caseMap: { [name: string]: number, } = {}; caseMap[s] = count; return new StringTypes(new Map([[s, count] as [string, number]]), new Set()); } - static fromCases(cases: string[]): StringTypes { - const caseMap: { [name: string]: number } = {}; + static fromCases (cases: string[]): StringTypes { + const caseMap: { [name: string]: number, } = {}; for (const s of cases) { caseMap[s] = 1; } + return new StringTypes(new Map(cases.map(s => [s, 1] as [string, number])), new Set()); } // undefined means no restrictions - constructor( + constructor ( readonly cases: ReadonlyMap | undefined, - readonly transformations: ReadonlySet + readonly transformations: ReadonlySet, ) { if (cases === undefined) { assert(transformations.size === 0, "We can't have an unrestricted string that also allows transformations"); } } - get isRestricted(): boolean { + get isRestricted (): boolean { return this.cases !== undefined; } - union(othersArray: StringTypes[], startIndex: number): StringTypes { + union (othersArray: StringTypes[], startIndex: number): StringTypes { if (this.cases === undefined) return this; const cases = new Map(this.cases); @@ -65,7 +67,7 @@ export class StringTypes { return new StringTypes(cases, transformations); } - intersect(othersArray: StringTypes[], startIndex: number): StringTypes { + intersect (othersArray: StringTypes[], startIndex: number): StringTypes { let cases = this.cases; let transformations = this.transformations; @@ -89,10 +91,11 @@ export class StringTypes { transformations = setIntersect(transformations, other.transformations); } + return new StringTypes(cases, transformations); } - applyStringTypeMapping(mapping: StringTypeMapping): StringTypes { + applyStringTypeMapping (mapping: StringTypeMapping): StringTypes { if (!this.isRestricted) return this; const kinds = new Set(); @@ -101,21 +104,22 @@ export class StringTypes { if (mapped === "string") return StringTypes.unrestricted; kinds.add(mapped); } + return new StringTypes(this.cases, new Set(kinds)); } - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof StringTypes)) return false; return areEqual(this.cases, other.cases) && areEqual(this.transformations, other.transformations); } - hashCode(): number { + hashCode (): number { let h = hashCodeOf(this.cases); h = addHashCode(h, hashCodeOf(this.transformations)); return h; } - toString(): string { + toString (): string { const parts: string[] = []; const enumCases = this.cases; @@ -135,33 +139,33 @@ export class StringTypes { } class StringTypesTypeAttributeKind extends TypeAttributeKind { - constructor() { + constructor () { super("stringTypes"); } - get inIdentity(): boolean { + get inIdentity (): boolean { return true; } - requiresUniqueIdentity(st: StringTypes): boolean { + requiresUniqueIdentity (st: StringTypes): boolean { return st.cases !== undefined && st.cases.size > 0; } - combine(arr: StringTypes[]): StringTypes { + combine (arr: StringTypes[]): StringTypes { assert(arr.length > 0); return arr[0].union(arr, 1); } - intersect(arr: StringTypes[]): StringTypes { + intersect (arr: StringTypes[]): StringTypes { assert(arr.length > 0); return arr[0].intersect(arr, 1); } - makeInferred(_: StringTypes): undefined { + makeInferred (_: StringTypes): undefined { return undefined; } - stringify(st: StringTypes): string { + stringify (st: StringTypes): string { return st.toString(); } } @@ -174,18 +178,19 @@ const INTEGER_STRING = /^(0|-?[1-9]\d*)$/; const MIN_INTEGER_STRING = 1 << 31; const MAX_INTEGER_STRING = -(MIN_INTEGER_STRING + 1); -function isIntegerString(s: string): boolean { - if (s.match(INTEGER_STRING) === null) { +function isIntegerString (s: string): boolean { + if (INTEGER_STRING.exec(s) === null) { return false; } + const i = parseInt(s, 10); return i >= MIN_INTEGER_STRING && i <= MAX_INTEGER_STRING; } const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; -function isUUID(s: string): boolean { - return s.match(UUID) !== null; +function isUUID (s: string): boolean { + return UUID.exec(s) !== null; } // FIXME: This is obviously not a complete URI regex. The exclusion of @@ -193,8 +198,8 @@ function isUUID(s: string): boolean { // with those characters which ajv refuses to accept as `uri`. const URI = /^(https?|ftp):\/\/[^{}]+$/; -function isURI(s: string): boolean { - return s.match(URI) !== null; +function isURI (s: string): boolean { + return URI.exec(s) !== null; } /** @@ -204,11 +209,11 @@ function isURI(s: string): boolean { * * @param s The string for which to determine the transformed string type kind. */ -export function inferTransformedStringTypeKindForString( +export function inferTransformedStringTypeKindForString ( s: string, - recognizer: DateTimeRecognizer + recognizer: DateTimeRecognizer, ): TransformedStringTypeKind | undefined { - if (s.length === 0 || "0123456789-abcdefth".indexOf(s[0]) < 0) return undefined; + if (s.length === 0 || !"0123456789-abcdefth".includes(s[0])) return undefined; if (recognizer.isDate(s)) { return "date"; @@ -225,5 +230,6 @@ export function inferTransformedStringTypeKindForString( } else if (isURI(s)) { return "uri"; } + return undefined; } diff --git a/packages/quicktype-core/src/attributes/TypeAttributes.ts b/packages/quicktype-core/src/attributes/TypeAttributes.ts index 1c73e8ffc..2077e0ca1 100644 --- a/packages/quicktype-core/src/attributes/TypeAttributes.ts +++ b/packages/quicktype-core/src/attributes/TypeAttributes.ts @@ -1,49 +1,49 @@ import { mapFilterMap, mapFilter, mapTranspose, hashString } from "collection-utils"; import { panic, assert } from "../support/Support"; -import { Type, TypeKind } from "../Type"; -import { BaseGraphRewriteBuilder } from "../GraphRewriting"; +import { type Type, type TypeKind } from "../Type"; +import { type BaseGraphRewriteBuilder } from "../GraphRewriting"; export class TypeAttributeKind { - constructor(readonly name: string) {} + constructor (readonly name: string) {} - appliesToTypeKind(kind: TypeKind): boolean { + appliesToTypeKind (kind: TypeKind): boolean { return kind !== "any"; } - combine(_attrs: T[]): T | undefined { + combine (_attrs: T[]): T | undefined { return panic(`Cannot combine type attribute ${this.name}`); } - intersect(attrs: T[]): T | undefined { + intersect (attrs: T[]): T | undefined { return this.combine(attrs); } - makeInferred(_: T): T | undefined { + makeInferred (_: T): T | undefined { return panic(`Cannot make type attribute ${this.name} inferred`); } - increaseDistance(attrs: T): T | undefined { + increaseDistance (attrs: T): T | undefined { return attrs; } - addToSchema(_schema: { [name: string]: unknown }, _t: Type, _attrs: T): void { + addToSchema (_schema: { [name: string]: unknown, }, _t: Type, _attrs: T): void { return; } - children(_: T): ReadonlySet { + children (_: T): ReadonlySet { return new Set(); } - stringify(_: T): string | undefined { + stringify (_: T): string | undefined { return undefined; } - get inIdentity(): boolean { + get inIdentity (): boolean { return false; } - requiresUniqueIdentity(_: T): boolean { + requiresUniqueIdentity (_: T): boolean { return false; } @@ -51,21 +51,21 @@ export class TypeAttributeKind { return a; } - makeAttributes(value: T): TypeAttributes { - const kvps: [this, T][] = [[this, value]]; + makeAttributes (value: T): TypeAttributes { + const kvps: Array<[this, T]> = [[this, value]]; return new Map(kvps); } - tryGetInAttributes(a: TypeAttributes): T | undefined { + tryGetInAttributes (a: TypeAttributes): T | undefined { return a.get(this); } - private setInAttributes(a: TypeAttributes, value: T): TypeAttributes { + private setInAttributes (a: TypeAttributes, value: T): TypeAttributes { // FIXME: This is potentially super slow return new Map(a).set(this, value); } - modifyInAttributes(a: TypeAttributes, modify: (value: T | undefined) => T | undefined): TypeAttributes { + modifyInAttributes (a: TypeAttributes, modify: (value: T | undefined) => T | undefined): TypeAttributes { const modified = modify(this.tryGetInAttributes(a)); if (modified === undefined) { // FIXME: This is potentially super slow @@ -73,26 +73,28 @@ export class TypeAttributeKind { result.delete(this); return result; } + return this.setInAttributes(a, modified); } - setDefaultInAttributes(a: TypeAttributes, makeDefault: () => T): TypeAttributes { + setDefaultInAttributes (a: TypeAttributes, makeDefault: () => T): TypeAttributes { if (this.tryGetInAttributes(a) !== undefined) return a; return this.modifyInAttributes(a, makeDefault); } - removeInAttributes(a: TypeAttributes): TypeAttributes { + removeInAttributes (a: TypeAttributes): TypeAttributes { return mapFilter(a, (_, k) => k !== this); } - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof TypeAttributeKind)) { return false; } + return this.name === other.name; } - hashCode(): number { + hashCode (): number { return hashString(this.name); } } @@ -103,12 +105,12 @@ export const emptyTypeAttributes: TypeAttributes = new Map(); export type CombinationKind = "union" | "intersect"; -export function combineTypeAttributes(kind: CombinationKind, attributeArray: TypeAttributes[]): TypeAttributes; -export function combineTypeAttributes(kind: CombinationKind, a: TypeAttributes, b: TypeAttributes): TypeAttributes; -export function combineTypeAttributes( +export function combineTypeAttributes (kind: CombinationKind, attributeArray: TypeAttributes[]): TypeAttributes; +export function combineTypeAttributes (kind: CombinationKind, a: TypeAttributes, b: TypeAttributes): TypeAttributes; +export function combineTypeAttributes ( combinationKind: CombinationKind, firstOrArray: TypeAttributes[] | TypeAttributes, - second?: TypeAttributes + second?: TypeAttributes, ): TypeAttributes { const union = combinationKind === "union"; let attributeArray: TypeAttributes[]; @@ -118,12 +120,13 @@ export function combineTypeAttributes( if (second === undefined) { return panic("Must have on array or two attributes"); } + attributeArray = [firstOrArray, second]; } const attributesByKind = mapTranspose(attributeArray); - function combine(attrs: any[], kind: TypeAttributeKind): any { + function combine (attrs: any[], kind: TypeAttributeKind): any { assert(attrs.length > 0, "Cannot combine zero type attributes"); if (attrs.length === 1) return attrs[0]; if (union) { @@ -136,10 +139,10 @@ export function combineTypeAttributes( return mapFilterMap(attributesByKind, combine); } -export function makeTypeAttributesInferred(attr: TypeAttributes): TypeAttributes { +export function makeTypeAttributesInferred (attr: TypeAttributes): TypeAttributes { return mapFilterMap(attr, (value, kind) => kind.makeInferred(value)); } -export function increaseTypeAttributesDistance(attr: TypeAttributes): TypeAttributes { +export function increaseTypeAttributesDistance (attr: TypeAttributes): TypeAttributes { return mapFilterMap(attr, (value, kind) => kind.increaseDistance(value)); } diff --git a/packages/quicktype-core/src/attributes/TypeNames.ts b/packages/quicktype-core/src/attributes/TypeNames.ts index c7225f3b7..119ebec14 100644 --- a/packages/quicktype-core/src/attributes/TypeNames.ts +++ b/packages/quicktype-core/src/attributes/TypeNames.ts @@ -2,21 +2,22 @@ import * as pluralize from "pluralize"; import { setMap, iterableFirst, iterableSkip, setUnionInto, definedMap } from "collection-utils"; import { panic, defined, assert } from "../support/Support"; -import { TypeAttributeKind, TypeAttributes } from "./TypeAttributes"; +import { type TypeAttributes } from "./TypeAttributes"; +import { TypeAttributeKind } from "./TypeAttributes"; import { splitIntoWords } from "../support/Strings"; import { Chance } from "../support/Chance"; let chance: Chance; let usedRandomNames: Set; -export function initTypeNames(): void { +export function initTypeNames (): void { chance = new Chance(31415); usedRandomNames = new Set(); } initTypeNames(); -function makeRandomName(): string { +function makeRandomName (): string { for (;;) { const name = `${chance.city()} ${chance.animal()}`; if (usedRandomNames.has(name)) continue; @@ -31,11 +32,12 @@ export type NameOrNames = string | TypeNames; // produce a name that includes the overlap twice. For example, for // the names "aaa" and "aaaa" we have the common prefix "aaa" and the // common suffix "aaa", so we will produce the combined name "aaaaaa". -function combineNames(names: ReadonlySet): string { +function combineNames (names: ReadonlySet): string { let originalFirst = iterableFirst(names); if (originalFirst === undefined) { return panic("Named type has no names"); } + if (names.size === 1) { return originalFirst; } @@ -43,7 +45,7 @@ function combineNames(names: ReadonlySet): string { const namesSet = setMap(names, s => splitIntoWords(s) .map(w => w.word.toLowerCase()) - .join("_") + .join("_"), ); const first = defined(iterableFirst(namesSet)); if (namesSet.size === 1) { @@ -69,22 +71,24 @@ function combineNames(names: ReadonlySet): string { } } } + const prefix = prefixLength > 2 ? first.slice(0, prefixLength) : ""; const suffix = suffixLength > 2 ? first.slice(first.length - suffixLength) : ""; const combined = prefix + suffix; if (combined.length > 2) { return combined; } + return first; } export const tooManyNamesThreshold = 1000; export abstract class TypeNames { - static makeWithDistance( + static makeWithDistance ( names: ReadonlySet, alternativeNames: ReadonlySet | undefined, - distance: number + distance: number, ): TypeNames { if (names.size >= tooManyNamesThreshold) { return new TooManyTypeNames(distance); @@ -97,41 +101,41 @@ export abstract class TypeNames { return new RegularTypeNames(names, alternativeNames, distance); } - static make( + static make ( names: ReadonlySet, alternativeNames: ReadonlySet | undefined, - areInferred: boolean + areInferred: boolean, ): TypeNames { return TypeNames.makeWithDistance(names, alternativeNames, areInferred ? 1 : 0); } - constructor(readonly distance: number) {} + constructor (readonly distance: number) {} - get areInferred(): boolean { + get areInferred (): boolean { return this.distance > 0; } - abstract get names(): ReadonlySet; - abstract get combinedName(): string; - abstract get proposedNames(): ReadonlySet; + abstract get names (): ReadonlySet; + abstract get combinedName (): string; + abstract get proposedNames (): ReadonlySet; - abstract add(namesArray: TypeNames[], startIndex?: number): TypeNames; - abstract clearInferred(): TypeNames; - abstract makeInferred(): TypeNames; - abstract singularize(): TypeNames; - abstract toString(): string; + abstract add (namesArray: TypeNames[], startIndex?: number): TypeNames; + abstract clearInferred (): TypeNames; + abstract makeInferred (): TypeNames; + abstract singularize (): TypeNames; + abstract toString (): string; } export class RegularTypeNames extends TypeNames { - constructor( + constructor ( readonly names: ReadonlySet, private readonly _alternativeNames: ReadonlySet | undefined, - distance: number + distance: number, ) { super(distance); } - add(namesArray: TypeNames[], startIndex = 0): TypeNames { + add (namesArray: TypeNames[], startIndex = 0): TypeNames { let newNames = new Set(this.names); let newDistance = this.distance; let newAlternativeNames = definedMap(this._alternativeNames, s => new Set(s)); @@ -143,6 +147,7 @@ export class RegularTypeNames extends TypeNames { if (newAlternativeNames === undefined) { newAlternativeNames = new Set(); } + setUnionInto(newAlternativeNames, other._alternativeNames); } @@ -165,45 +170,48 @@ export class RegularTypeNames extends TypeNames { setUnionInto(newNames, other.names); } } + return TypeNames.makeWithDistance(newNames, newAlternativeNames, newDistance); } - clearInferred(): TypeNames { + clearInferred (): TypeNames { const newNames = this.areInferred ? new Set() : this.names; return TypeNames.makeWithDistance(newNames, new Set(), this.distance); } - get combinedName(): string { + get combinedName (): string { return combineNames(this.names); } - get proposedNames(): ReadonlySet { + get proposedNames (): ReadonlySet { const set = new Set([this.combinedName]); if (this._alternativeNames === undefined) { return set; } + setUnionInto(set, this._alternativeNames); return set; } - makeInferred(): TypeNames { + makeInferred (): TypeNames { return TypeNames.makeWithDistance(this.names, this._alternativeNames, this.distance + 1); } - singularize(): TypeNames { + singularize (): TypeNames { return TypeNames.makeWithDistance( setMap(this.names, pluralize.singular), definedMap(this._alternativeNames, an => setMap(an, pluralize.singular)), - this.distance + 1 + this.distance + 1, ); } - toString(): string { + toString (): string { const inferred = this.areInferred ? `distance ${this.distance}` : "given"; const names = `${inferred} ${Array.from(this.names).join(",")}`; if (this._alternativeNames === undefined) { return names; } + return `${names} (${Array.from(this._alternativeNames).join(",")})`; } } @@ -211,24 +219,25 @@ export class RegularTypeNames extends TypeNames { export class TooManyTypeNames extends TypeNames { readonly names: ReadonlySet; - constructor(distance: number, name?: string) { + constructor (distance: number, name?: string) { super(distance); if (name === undefined) { name = makeRandomName(); } + this.names = new Set([name]); } - get combinedName(): string { + get combinedName (): string { return defined(iterableFirst(this.names)); } - get proposedNames(): ReadonlySet { + get proposedNames (): ReadonlySet { return this.names; } - add(namesArray: TypeNames[], startIndex = 0): TypeNames { + add (namesArray: TypeNames[], startIndex = 0): TypeNames { if (!this.areInferred) return this; for (let i = startIndex; i < namesArray.length; i++) { @@ -241,72 +250,74 @@ export class TooManyTypeNames extends TypeNames { return this; } - clearInferred(): TypeNames { + clearInferred (): TypeNames { if (!this.areInferred) { return this; } + return TypeNames.makeWithDistance(new Set(), new Set(), this.distance); } - makeInferred(): TypeNames { + makeInferred (): TypeNames { return new TooManyTypeNames(this.distance + 1, iterableFirst(this.names)); } - singularize(): TypeNames { + singularize (): TypeNames { return this; } - toString(): string { + toString (): string { return `too many ${this.combinedName}`; } } class TypeNamesTypeAttributeKind extends TypeAttributeKind { - constructor() { + constructor () { super("names"); } - combine(namesArray: TypeNames[]): TypeNames { + combine (namesArray: TypeNames[]): TypeNames { assert(namesArray.length > 0, "Can't combine zero type names"); return namesArray[0].add(namesArray, 1); } - makeInferred(tn: TypeNames): TypeNames { + makeInferred (tn: TypeNames): TypeNames { return tn.makeInferred(); } - increaseDistance(tn: TypeNames): TypeNames { + increaseDistance (tn: TypeNames): TypeNames { return tn.makeInferred(); } - stringify(tn: TypeNames): string { + stringify (tn: TypeNames): string { return tn.toString(); } } export const namesTypeAttributeKind: TypeAttributeKind = new TypeNamesTypeAttributeKind(); -export function modifyTypeNames( +export function modifyTypeNames ( attributes: TypeAttributes, - modifier: (tn: TypeNames | undefined) => TypeNames | undefined + modifier: (tn: TypeNames | undefined) => TypeNames | undefined, ): TypeAttributes { return namesTypeAttributeKind.modifyInAttributes(attributes, modifier); } -export function singularizeTypeNames(attributes: TypeAttributes): TypeAttributes { +export function singularizeTypeNames (attributes: TypeAttributes): TypeAttributes { return modifyTypeNames(attributes, maybeNames => { if (maybeNames === undefined) return undefined; return maybeNames.singularize(); }); } -export function makeNamesTypeAttributes(nameOrNames: NameOrNames, areNamesInferred?: boolean): TypeAttributes { +export function makeNamesTypeAttributes (nameOrNames: NameOrNames, areNamesInferred?: boolean): TypeAttributes { let typeNames: TypeNames; if (typeof nameOrNames === "string") { typeNames = TypeNames.make(new Set([nameOrNames]), new Set(), defined(areNamesInferred)); } else { typeNames = nameOrNames as TypeNames; } + return namesTypeAttributeKind.makeAttributes(typeNames); } diff --git a/packages/quicktype-core/src/attributes/URIAttributes.ts b/packages/quicktype-core/src/attributes/URIAttributes.ts index 1f779708b..3213a389c 100644 --- a/packages/quicktype-core/src/attributes/URIAttributes.ts +++ b/packages/quicktype-core/src/attributes/URIAttributes.ts @@ -1,11 +1,12 @@ import URI from "urijs"; -import { TypeAttributeKind, TypeAttributes, emptyTypeAttributes } from "./TypeAttributes"; +import { type TypeAttributes} from "./TypeAttributes"; +import { TypeAttributeKind, emptyTypeAttributes } from "./TypeAttributes"; import { setUnionManyInto } from "collection-utils"; -import { JSONSchemaType, JSONSchemaAttributes, Ref } from "../input/JSONSchemaInput"; -import { JSONSchema } from "../input/JSONSchemaStore"; +import { type JSONSchemaType, type JSONSchemaAttributes, type Ref } from "../input/JSONSchemaInput"; +import { type JSONSchema } from "../input/JSONSchemaStore"; import { checkArray, checkString } from "../support/Support"; -import { Type } from "../Type"; +import { type Type } from "../Type"; const protocolsSchemaProperty = "qt-uri-protocols"; const extensionsSchemaProperty = "qt-uri-extensions"; @@ -14,31 +15,32 @@ const extensionsSchemaProperty = "qt-uri-extensions"; type URIAttributes = [ReadonlySet, ReadonlySet]; class URITypeAttributeKind extends TypeAttributeKind { - constructor() { + constructor () { super("uriAttributes"); } - get inIdentity(): boolean { + get inIdentity (): boolean { return true; } - combine(attrs: URIAttributes[]): URIAttributes { + combine (attrs: URIAttributes[]): URIAttributes { const protocolSets = attrs.map(a => a[0]); const extensionSets = attrs.map(a => a[1]); return [setUnionManyInto(new Set(), protocolSets), setUnionManyInto(new Set(), extensionSets)]; } - makeInferred(_: URIAttributes): undefined { + makeInferred (_: URIAttributes): undefined { return undefined; } - addToSchema(schema: { [name: string]: unknown }, t: Type, attrs: URIAttributes): void { + addToSchema (schema: { [name: string]: unknown, }, t: Type, attrs: URIAttributes): void { if (t.kind !== "string" && t.kind !== "uri") return; const [protocols, extensions] = attrs; if (protocols.size > 0) { schema[protocolsSchemaProperty] = Array.from(protocols).sort(); } + if (extensions.size > 0) { schema[extensionsSchemaProperty] = Array.from(extensions).sort(); } @@ -49,13 +51,13 @@ export const uriTypeAttributeKind: TypeAttributeKind = new URITyp const extensionRegex = /^.+(\.[^./\\]+)$/; -function pathExtension(path: string): string | undefined { - const matches = path.match(extensionRegex); +function pathExtension (path: string): string | undefined { + const matches = extensionRegex.exec(path); if (matches === null) return undefined; return matches[1]; } -export function uriInferenceAttributesProducer(s: string): TypeAttributes { +export function uriInferenceAttributesProducer (s: string): TypeAttributes { try { const uri = URI(s); const extension = pathExtension(uri.path()); @@ -66,10 +68,10 @@ export function uriInferenceAttributesProducer(s: string): TypeAttributes { } } -export function uriSchemaAttributesProducer( +export function uriSchemaAttributesProducer ( schema: JSONSchema, _ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!(typeof schema === "object")) return undefined; if (!types.has("string")) return undefined; diff --git a/packages/quicktype-core/src/index.ts b/packages/quicktype-core/src/index.ts index aa04f0857..a56413a31 100644 --- a/packages/quicktype-core/src/index.ts +++ b/packages/quicktype-core/src/index.ts @@ -1,6 +1,6 @@ export { - Options, - RendererOptions, + type Options, + type RendererOptions, getTargetLanguage, quicktypeMultiFile, quicktypeMultiFileSync, @@ -10,26 +10,26 @@ export { inferenceFlagNames, defaultInferenceFlags, inferenceFlagsObject, - InferenceFlags, - InferenceFlagName, - RunContext + type InferenceFlags, + type InferenceFlagName, + type RunContext, } from "./Run"; -export { CompressedJSON, Value } from "./input/CompressedJSON"; -export { Input, InputData, JSONInput, JSONSourceData, jsonInputForTargetLanguage } from "./input/Inputs"; -export { JSONSchemaInput, JSONSchemaSourceData } from "./input/JSONSchemaInput"; -export { Ref, JSONSchemaType, JSONSchemaAttributes } from "./input/JSONSchemaInput"; -export { RenderContext } from "./Renderer"; -export { Option, OptionDefinition, getOptionValues, OptionValues } from "./RendererOptions"; -export { TargetLanguage, MultiFileRenderResult } from "./TargetLanguage"; +export { CompressedJSON, type Value } from "./input/CompressedJSON"; +export { type Input, InputData, JSONInput, type JSONSourceData, jsonInputForTargetLanguage } from "./input/Inputs"; +export { JSONSchemaInput, type JSONSchemaSourceData } from "./input/JSONSchemaInput"; +export { Ref, type JSONSchemaType, type JSONSchemaAttributes } from "./input/JSONSchemaInput"; +export type { RenderContext } from "./Renderer"; +export { Option, type OptionDefinition, getOptionValues, type OptionValues } from "./RendererOptions"; +export { TargetLanguage, type MultiFileRenderResult } from "./TargetLanguage"; export { all as defaultTargetLanguages, languageNamed } from "./language/All"; export { - MultiWord, - Sourcelike, - SerializedRenderResult, - Annotation, + type MultiWord, + type Sourcelike, + type SerializedRenderResult, + type Annotation, modifySource, singleWord, - parenIfNeeded + parenIfNeeded, } from "./Source"; export { Name, funPrefixNamer, Namer } from "./Naming"; export { IssueAnnotationData } from "./Annotation"; @@ -41,7 +41,7 @@ export { parseJSON, checkStringMap, checkArray, - inflateBase64 + inflateBase64, } from "./support/Support"; export { splitIntoWords, @@ -50,7 +50,7 @@ export { firstUpperWordStyle, allUpperWordStyle, legalizeCharacters, - isLetterOrDigit + isLetterOrDigit, } from "./support/Strings"; export { train as trainMarkovChain } from "./MarkovChain"; export { QuickTypeError, messageError, messageAssert } from "./Messages"; @@ -63,19 +63,19 @@ export { EnumType, MapType, UnionType, - TypeKind, + type TypeKind, ObjectType, - TransformedStringTypeKind, - PrimitiveStringTypeKind + type TransformedStringTypeKind, + type PrimitiveStringTypeKind, } from "./Type"; export { getStream } from "./input/io/get-stream"; export { readableFromFileOrURL, readFromFileOrURL } from "./input/io/NodeIO"; export { FetchingJSONSchemaStore } from "./input/FetchingJSONSchemaStore"; -export { JSONSchemaStore, JSONSchema } from "./input/JSONSchemaStore"; +export { JSONSchemaStore, type JSONSchema } from "./input/JSONSchemaStore"; export { sourcesFromPostmanCollection } from "./input/PostmanCollection"; -export { TypeBuilder, StringTypeMapping } from "./TypeBuilder"; -export { TypeRef, derefTypeRef } from "./TypeGraph"; -export { TypeAttributeKind, TypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +export { TypeBuilder, type StringTypeMapping } from "./TypeBuilder"; +export { type TypeRef, derefTypeRef } from "./TypeGraph"; +export { TypeAttributeKind, type TypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; export { TypeNames, makeNamesTypeAttributes, namesTypeAttributeKind } from "./attributes/TypeNames"; export { StringTypes } from "./attributes/StringTypes"; export { removeNullFromUnion, matchType, nullableFromUnion } from "./TypeUtils"; @@ -93,14 +93,14 @@ export { JavaScriptTargetLanguage, JavaScriptRenderer, javaScriptOptions } from export { JavaScriptPropTypesTargetLanguage, JavaScriptPropTypesRenderer, - javaScriptPropTypesOptions + javaScriptPropTypesOptions, } from "./language/JavaScriptPropTypes"; export { TypeScriptTargetLanguage, TypeScriptRenderer, FlowTargetLanguage, FlowRenderer, - tsFlowOptions + tsFlowOptions, } from "./language/TypeScriptFlow"; export { SwiftTargetLanguage, SwiftRenderer, swiftOptions } from "./language/Swift"; export { KotlinTargetLanguage, KotlinRenderer, kotlinOptions } from "./language/Kotlin"; diff --git a/packages/quicktype-core/src/input/CompressedJSON.ts b/packages/quicktype-core/src/input/CompressedJSON.ts index 2bdb2cc85..7832c0675 100644 --- a/packages/quicktype-core/src/input/CompressedJSON.ts +++ b/packages/quicktype-core/src/input/CompressedJSON.ts @@ -1,8 +1,9 @@ import { addHashCode, hashCodeInit, hashString } from "collection-utils"; import { defined, panic, assert } from "../support/Support"; -import { TransformedStringTypeKind, isPrimitiveStringTypeKind, transformedStringTypeTargetTypeKindsMap } from "../Type"; -import { DateTimeRecognizer } from "../DateTime"; +import { type TransformedStringTypeKind} from "../Type"; +import { isPrimitiveStringTypeKind, transformedStringTypeTargetTypeKindsMap } from "../Type"; +import { type DateTimeRecognizer } from "../DateTime"; import { inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; export enum Tag { @@ -24,46 +25,50 @@ export type Value = number; const TAG_BITS = 4; const TAG_MASK = (1 << TAG_BITS) - 1; -export function makeValue(t: Tag, index: number): Value { - return t | (index << TAG_BITS); +export function makeValue (t: Tag, index: number): Value { + return t | index << TAG_BITS; } -function getIndex(v: Value, tag: Tag): number { +function getIndex (v: Value, tag: Tag): number { assert(valueTag(v) === tag, "Trying to get index for value with invalid tag"); return v >> TAG_BITS; } -export function valueTag(v: Value): Tag { +export function valueTag (v: Value): Tag { return v & TAG_MASK; } -type Context = { - currentObject: Value[] | undefined; +interface Context { currentArray: Value[] | undefined; currentKey: string | undefined; currentNumberIsDouble: boolean; -}; + currentObject: Value[] | undefined; +} export abstract class CompressedJSON { private _rootValue: Value | undefined; private _ctx: Context | undefined; + private _contextStack: Context[] = []; private _strings: string[] = []; - private _stringIndexes: { [str: string]: number } = {}; + + private _stringIndexes: { [str: string]: number, } = {}; + private _objects: Value[][] = []; + private _arrays: Value[][] = []; - constructor(readonly dateTimeRecognizer: DateTimeRecognizer, readonly handleRefs: boolean) {} + constructor (readonly dateTimeRecognizer: DateTimeRecognizer, readonly handleRefs: boolean) {} - abstract parse(input: T): Promise; + abstract parse (input: T): Promise; - parseSync(_input: T): Value { + parseSync (_input: T): Value { return panic("parseSync not implemented in CompressedJSON"); } - getStringForValue(v: Value): string { + getStringForValue (v: Value): string { const tag = valueTag(v); assert(tag === Tag.InternedString || tag === Tag.TransformedString); return this._strings[getIndex(v, tag)]; @@ -77,35 +82,37 @@ export abstract class CompressedJSON { return this._arrays[getIndex(v, Tag.Array)]; }; - getStringFormatTypeKind(v: Value): TransformedStringTypeKind { + getStringFormatTypeKind (v: Value): TransformedStringTypeKind { const kind = this._strings[getIndex(v, Tag.StringFormat)]; if (!isPrimitiveStringTypeKind(kind) || kind === "string") { return panic("Not a transformed string type kind"); } + return kind; } - protected get context(): Context { + protected get context (): Context { return defined(this._ctx); } - protected internString(s: string): number { + protected internString (s: string): number { if (Object.prototype.hasOwnProperty.call(this._stringIndexes, s)) { return this._stringIndexes[s]; } + const index = this._strings.length; this._strings.push(s); this._stringIndexes[s] = index; return index; } - protected makeString(s: string): Value { + protected makeString (s: string): Value { const value = makeValue(Tag.InternedString, this.internString(s)); assert(typeof value === "number", `Interned string value is not a number: ${value}`); return value; } - protected internObject(obj: Value[]): Value { + protected internObject (obj: Value[]): Value { const index = this._objects.length; this._objects.push(obj); return makeValue(Tag.Object, index); @@ -117,22 +124,23 @@ export abstract class CompressedJSON { return makeValue(Tag.Array, index); }; - protected get isExpectingRef(): boolean { + protected get isExpectingRef (): boolean { return this._ctx !== undefined && this._ctx.currentKey === "$ref"; } - protected commitValue(value: Value): void { + protected commitValue (value: Value): void { assert(typeof value === "number", `CompressedJSON value is not a number: ${value}`); if (this._ctx === undefined) { assert( this._rootValue === undefined, - "Committing value but nowhere to commit to - root value still there." + "Committing value but nowhere to commit to - root value still there.", ); this._rootValue = value; } else if (this._ctx.currentObject !== undefined) { if (this._ctx.currentKey === undefined) { return panic("Must have key and can't have string when committing"); } + this._ctx.currentObject.push(this.makeString(this._ctx.currentKey), value); this._ctx.currentKey = undefined; } else if (this._ctx.currentArray !== undefined) { @@ -142,20 +150,20 @@ export abstract class CompressedJSON { } } - protected commitNull(): void { + protected commitNull (): void { this.commitValue(makeValue(Tag.Null, 0)); } - protected commitBoolean(v: boolean): void { + protected commitBoolean (v: boolean): void { this.commitValue(makeValue(v ? Tag.True : Tag.False, 0)); } - protected commitNumber(isDouble: boolean): void { + protected commitNumber (isDouble: boolean): void { const numberTag = isDouble ? Tag.Double : Tag.Integer; this.commitValue(makeValue(numberTag, 0)); } - protected commitString(s: string): void { + protected commitString (s: string): void { let value: Value | undefined = undefined; if (this.handleRefs && this.isExpectingRef) { value = this.makeString(s); @@ -173,74 +181,79 @@ export abstract class CompressedJSON { value = makeValue(Tag.UninternedString, 0); } } + this.commitValue(value); } - protected finish(): Value { + protected finish (): Value { const value = this._rootValue; if (value === undefined) { return panic("Finished without root document"); } + assert(this._ctx === undefined && this._contextStack.length === 0, "Finished with contexts present"); this._rootValue = undefined; return value; } - protected pushContext(): void { + protected pushContext (): void { if (this._ctx !== undefined) { this._contextStack.push(this._ctx); } + this._ctx = { currentObject: undefined, currentArray: undefined, currentKey: undefined, - currentNumberIsDouble: false + currentNumberIsDouble: false, }; } - protected pushObjectContext(): void { + protected pushObjectContext (): void { this.pushContext(); defined(this._ctx).currentObject = []; } - protected setPropertyKey(key: string): void { + protected setPropertyKey (key: string): void { const ctx = this.context; ctx.currentKey = key; } - protected finishObject(): void { + protected finishObject (): void { const obj = this.context.currentObject; if (obj === undefined) { return panic("Object ended but not started"); } + this.popContext(); this.commitValue(this.internObject(obj)); } - protected pushArrayContext(): void { + protected pushArrayContext (): void { this.pushContext(); defined(this._ctx).currentArray = []; } - protected finishArray(): void { + protected finishArray (): void { const arr = this.context.currentArray; if (arr === undefined) { return panic("Array ended but not started"); } + this.popContext(); this.commitValue(this.internArray(arr)); } - protected popContext(): void { + protected popContext (): void { assert(this._ctx !== undefined, "Popping context when there isn't one"); this._ctx = this._contextStack.pop(); } - equals(other: any): boolean { + equals (other: any): boolean { return this === other; } - hashCode(): number { + hashCode (): number { let hashAccumulator = hashCodeInit; for (const s of this._strings) { hashAccumulator = addHashCode(hashAccumulator, hashString(s)); @@ -256,6 +269,7 @@ export abstract class CompressedJSON { hashAccumulator = addHashCode(hashAccumulator, v); } } + for (const o of this._arrays) { for (const v of o) { hashAccumulator = addHashCode(hashAccumulator, v); @@ -267,17 +281,17 @@ export abstract class CompressedJSON { } export class CompressedJSONFromString extends CompressedJSON { - async parse(input: string): Promise { + async parse (input: string): Promise { return this.parseSync(input); } - parseSync(input: string): Value { + parseSync (input: string): Value { const json = JSON.parse(input); this.process(json); return this.finish(); } - private process(json: unknown): void { + private process (json: unknown): void { if (json === null) { this.commitNull(); } else if (typeof json === "boolean") { @@ -293,6 +307,7 @@ export class CompressedJSONFromString extends CompressedJSON { for (const v of json) { this.process(v); } + this.finishArray(); } else if (typeof json === "object") { this.pushObjectContext(); @@ -300,6 +315,7 @@ export class CompressedJSONFromString extends CompressedJSON { this.setPropertyKey(key); this.process((json as any)[key]); } + this.finishObject(); } else { return panic("Invalid JSON object"); diff --git a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts index 08c6e0526..113baf372 100644 --- a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts @@ -1,13 +1,14 @@ -import { JSONSchema, JSONSchemaStore } from "./JSONSchemaStore"; +import { type JSONSchema} from "./JSONSchemaStore"; +import { JSONSchemaStore } from "./JSONSchemaStore"; import { parseJSON } from ".."; import { readFromFileOrURL } from "./io/NodeIO"; export class FetchingJSONSchemaStore extends JSONSchemaStore { - constructor(private readonly _httpHeaders?: string[]) { + constructor (private readonly _httpHeaders?: string[]) { super(); } - async fetch(address: string): Promise { + async fetch (address: string): Promise { // console.log(`Fetching ${address}`); return parseJSON(await readFromFileOrURL(address, this._httpHeaders), "JSON Schema", address); } diff --git a/packages/quicktype-core/src/input/Inference.ts b/packages/quicktype-core/src/input/Inference.ts index 9fdcea588..272c15d61 100644 --- a/packages/quicktype-core/src/input/Inference.ts +++ b/packages/quicktype-core/src/input/Inference.ts @@ -1,18 +1,22 @@ -import { Value, Tag, valueTag, CompressedJSON } from "./CompressedJSON"; +import { type Value, type CompressedJSON } from "./CompressedJSON"; +import { Tag, valueTag } from "./CompressedJSON"; import { assertNever, defined, panic, assert } from "../support/Support"; -import { TypeBuilder } from "../TypeBuilder"; +import { type TypeBuilder } from "../TypeBuilder"; import { UnionBuilder, UnionAccumulator } from "../UnionBuilder"; import { - ClassProperty, + type ClassProperty} from "../Type"; +import { transformedStringTypeTargetTypeKindsMap, UnionType, ClassType, MapType, - ArrayType + ArrayType, } from "../Type"; -import { TypeAttributes, emptyTypeAttributes } from "../attributes/TypeAttributes"; +import { type TypeAttributes} from "../attributes/TypeAttributes"; +import { emptyTypeAttributes } from "../attributes/TypeAttributes"; import { StringTypes, inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; -import { TypeRef, derefTypeRef } from "../TypeGraph"; +import { type TypeRef} from "../TypeGraph"; +import { derefTypeRef } from "../TypeGraph"; import { messageError } from "../Messages"; import { nullableFromUnion } from "../TypeUtils"; @@ -21,10 +25,11 @@ import { nullableFromUnion } from "../TypeUtils"; // but TypeScript doesn't support that. export type NestedValueArray = any; -function forEachArrayInNestedValueArray(va: NestedValueArray, f: (va: Value[]) => void): void { +function forEachArrayInNestedValueArray (va: NestedValueArray, f: (va: Value[]) => void): void { if (va.length === 0) { return; } + if (Array.isArray(va[0])) { for (const x of va) { forEachArrayInNestedValueArray(x, f); @@ -34,7 +39,7 @@ function forEachArrayInNestedValueArray(va: NestedValueArray, f: (va: Value[]) = } } -function forEachValueInNestedValueArray(va: NestedValueArray, f: (v: Value) => void): void { +function forEachValueInNestedValueArray (va: NestedValueArray, f: (v: Value) => void): void { forEachArrayInNestedValueArray(va, a => { for (const x of a) { f(x); @@ -43,51 +48,51 @@ function forEachValueInNestedValueArray(va: NestedValueArray, f: (v: Value) => v } class InferenceUnionBuilder extends UnionBuilder { - constructor( + constructor ( typeBuilder: TypeBuilder, private readonly _typeInference: TypeInference, - private readonly _fixed: boolean + private readonly _fixed: boolean, ) { super(typeBuilder); } - protected makeObject( + protected makeObject ( objects: NestedValueArray, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { return this._typeInference.inferClassType(typeAttributes, objects, this._fixed, forwardingRef); } - protected makeArray( + protected makeArray ( arrays: NestedValueArray, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { return this.typeBuilder.getArrayType( typeAttributes, - this._typeInference.inferType(emptyTypeAttributes, arrays, this._fixed, forwardingRef) + this._typeInference.inferType(emptyTypeAttributes, arrays, this._fixed, forwardingRef), ); } } -function canBeEnumCase(_s: string): boolean { +function canBeEnumCase (_s: string): boolean { return true; } export type Accumulator = UnionAccumulator; export class TypeInference { - private _refIntersections: [TypeRef, string[]][] | undefined; + private _refIntersections: Array<[TypeRef, string[]]> | undefined; - constructor( + constructor ( private readonly _cjson: CompressedJSON, private readonly _typeBuilder: TypeBuilder, private readonly _inferMaps: boolean, - private readonly _inferEnums: boolean + private readonly _inferEnums: boolean, ) {} - addValuesToAccumulator(valueArray: NestedValueArray, accumulator: Accumulator): void { + addValuesToAccumulator (valueArray: NestedValueArray, accumulator: Accumulator): void { forEachValueInNestedValueArray(valueArray, value => { const t = valueTag(value); switch (t) { @@ -115,6 +120,7 @@ export class TypeInference { } else { accumulator.addStringType("string", emptyTypeAttributes); } + break; case Tag.UninternedString: accumulator.addStringType("string", emptyTypeAttributes); @@ -130,43 +136,48 @@ export class TypeInference { accumulator.addStringType( "string", emptyTypeAttributes, - new StringTypes(new Map(), new Set([kind])) + new StringTypes(new Map(), new Set([kind])), ); break; } + case Tag.TransformedString: { const s = this._cjson.getStringForValue(value); const kind = inferTransformedStringTypeKindForString(s, this._cjson.dateTimeRecognizer); if (kind === undefined) { return panic("TransformedString does not have a kind"); } + const producer = defined(transformedStringTypeTargetTypeKindsMap.get(kind)).attributesProducer; if (producer === undefined) { return panic("TransformedString does not have attribute producer"); } + accumulator.addStringType("string", producer(s), new StringTypes(new Map(), new Set([kind]))); break; } + default: return assertNever(t); } }); } - inferType( + inferType ( typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { const accumulator = this.accumulatorForArray(valueArray); return this.makeTypeFromAccumulator(accumulator, typeAttributes, fixed, forwardingRef); } - private resolveRef(ref: string, topLevel: TypeRef): TypeRef { + private resolveRef (ref: string, topLevel: TypeRef): TypeRef { if (!ref.startsWith("#/")) { return messageError("InferenceJSONReferenceNotRooted", { reference: ref }); } + const parts = ref.split("/").slice(1); const graph = this._typeBuilder.typeGraph; let tref = topLevel; @@ -178,33 +189,39 @@ export class TypeInference { // FIXME: handle unions return messageError("InferenceJSONReferenceToUnion", { reference: ref }); } + t = nullable; } + if (t instanceof ClassType) { const cp = t.getProperties().get(part); if (cp === undefined) { return messageError("InferenceJSONReferenceWrongProperty", { reference: ref }); } + tref = cp.typeRef; } else if (t instanceof MapType) { tref = t.values.typeRef; } else if (t instanceof ArrayType) { - if (part.match("^[0-9]+$") === null) { + if (/^[0-9]+$/.exec(part) === null) { return messageError("InferenceJSONReferenceInvalidArrayIndex", { reference: ref }); } + tref = t.items.typeRef; } else { return messageError("InferenceJSONReferenceWrongProperty", { reference: ref }); } } + return tref; } - inferTopLevelType(typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean): TypeRef { + inferTopLevelType (typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean): TypeRef { assert(this._refIntersections === undefined, "Didn't reset ref intersections - nested invocations?"); if (this._cjson.handleRefs) { this._refIntersections = []; } + const topLevel = this.inferType(typeAttributes, valueArray, fixed); if (this._cjson.handleRefs) { for (const [tref, refs] of defined(this._refIntersections)) { @@ -214,33 +231,34 @@ export class TypeInference { this._refIntersections = undefined; } + return topLevel; } - accumulatorForArray(valueArray: NestedValueArray): Accumulator { + accumulatorForArray (valueArray: NestedValueArray): Accumulator { const accumulator = new UnionAccumulator(true); this.addValuesToAccumulator(valueArray, accumulator); return accumulator; } - makeTypeFromAccumulator( + makeTypeFromAccumulator ( accumulator: Accumulator, typeAttributes: TypeAttributes, fixed: boolean, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { const unionBuilder = new InferenceUnionBuilder(this._typeBuilder, this, fixed); return unionBuilder.buildUnion(accumulator, false, typeAttributes, forwardingRef); } - inferClassType( + inferClassType ( typeAttributes: TypeAttributes, objects: NestedValueArray, fixed: boolean, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { const propertyNames: string[] = []; - const propertyValues: { [name: string]: Value[] } = {}; + const propertyValues: { [name: string]: Value[], } = {}; forEachArrayInNestedValueArray(objects, arr => { for (let i = 0; i < arr.length; i += 2) { @@ -250,12 +268,13 @@ export class TypeInference { propertyNames.push(key); propertyValues[key] = []; } + propertyValues[key].push(value); } }); if (this._cjson.handleRefs && propertyNames.length === 1 && propertyNames[0] === "$ref") { - const values = propertyValues["$ref"]; + const values = propertyValues.$ref; if (values.every(v => valueTag(v) === Tag.InternedString)) { const allRefs = values.map(v => this._cjson.getStringForValue(v)); // FIXME: Add is-ref attribute @@ -270,6 +289,7 @@ export class TypeInference { for (const key of propertyNames) { this.addValuesToAccumulator(propertyValues[key], accumulator); } + const values = this.makeTypeFromAccumulator(accumulator, emptyTypeAttributes, fixed); return this._typeBuilder.getMapType(typeAttributes, values, forwardingRef); } diff --git a/packages/quicktype-core/src/input/Inputs.ts b/packages/quicktype-core/src/input/Inputs.ts index 9ff8905fa..4d9ebc1de 100644 --- a/packages/quicktype-core/src/input/Inputs.ts +++ b/packages/quicktype-core/src/input/Inputs.ts @@ -1,85 +1,92 @@ import { iterableFirst, iterableFind, iterableSome, setFilterMap, withDefault, arrayMapSync } from "collection-utils"; -import { Value, CompressedJSON, CompressedJSONFromString } from "./CompressedJSON"; +import { type Value, type CompressedJSON} from "./CompressedJSON"; +import { CompressedJSONFromString } from "./CompressedJSON"; import { panic, errorMessage, defined } from "../support/Support"; import { messageError } from "../Messages"; -import { TypeBuilder } from "../TypeBuilder"; +import { type TypeBuilder } from "../TypeBuilder"; import { makeNamesTypeAttributes } from "../attributes/TypeNames"; import { descriptionTypeAttributeKind } from "../attributes/Description"; import { TypeInference } from "./Inference"; -import { TargetLanguage } from "../TargetLanguage"; -import { RunContext } from "../Run"; +import { type TargetLanguage } from "../TargetLanguage"; +import { type RunContext } from "../Run"; import { languageNamed } from "../language/All"; export interface Input { - readonly kind: string; - readonly needIR: boolean; - readonly needSchemaProcessing: boolean; - - addSource(source: T): Promise; - addSourceSync(source: T): void; - - singleStringSchemaSource(): string | undefined; - - addTypes( + addSource: (source: T) => Promise; + addSourceSync: (source: T) => void; + addTypes: ( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, fixedTopLevels: boolean - ): Promise; - addTypesSync( + ) => Promise; + + addTypesSync: ( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, fixedTopLevels: boolean - ): void; + ) => void; + readonly kind: string; + + readonly needIR: boolean; + + readonly needSchemaProcessing: boolean; + singleStringSchemaSource: () => string | undefined; } -type JSONTopLevel = { samples: Value[]; description: string | undefined }; +interface JSONTopLevel { + description: string | undefined; samples: Value[]; +} export interface JSONSourceData { + description?: string; name: string; samples: T[]; - description?: string; } -function messageParseError(name: string, description: string | undefined, e: unknown): never { +function messageParseError (name: string, description: string | undefined, e: unknown): never { return messageError("MiscJSONParseError", { description: withDefault(description, "input"), address: name, - message: errorMessage(e) + message: errorMessage(e), }); } export class JSONInput implements Input> { readonly kind: string = "json"; + readonly needIR: boolean = true; + readonly needSchemaProcessing: boolean = false; private readonly _topLevels: Map = new Map(); - constructor(private readonly _compressedJSON: CompressedJSON) {} + constructor (private readonly _compressedJSON: CompressedJSON) {} - private addSample(topLevelName: string, sample: Value): void { + private addSample (topLevelName: string, sample: Value): void { let topLevel = this._topLevels.get(topLevelName); if (topLevel === undefined) { topLevel = { samples: [], description: undefined }; this._topLevels.set(topLevelName, topLevel); } + topLevel.samples.push(sample); } - private setDescription(topLevelName: string, description: string): void { + private setDescription (topLevelName: string, description: string): void { let topLevel = this._topLevels.get(topLevelName); if (topLevel === undefined) { return panic("Trying to set description for a top-level that doesn't exist"); } + topLevel.description = description; } - private addSamples(name: string, values: Value[], description: string | undefined): void { + private addSamples (name: string, values: Value[], description: string | undefined): void { for (const value of values) { this.addSample(name, value); if (description !== undefined) { @@ -88,7 +95,7 @@ export class JSONInput implements Input> { } } - async addSource(source: JSONSourceData): Promise { + async addSource (source: JSONSourceData): Promise { const { name, samples, description } = source; try { const values = await arrayMapSync(samples, async s => await this._compressedJSON.parse(s)); @@ -98,7 +105,7 @@ export class JSONInput implements Input> { } } - addSourceSync(source: JSONSourceData): void { + addSourceSync (source: JSONSourceData): void { const { name, samples, description } = source; try { const values = samples.map(s => this._compressedJSON.parseSync(s)); @@ -108,26 +115,26 @@ export class JSONInput implements Input> { } } - singleStringSchemaSource(): undefined { + singleStringSchemaSource (): undefined { return undefined; } - async addTypes( + async addTypes ( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ): Promise { - return this.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); + this.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); } - addTypesSync( + addTypesSync ( _ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ): void { const inference = new TypeInference(this._compressedJSON, typeBuilder, inferMaps, inferEnums); @@ -142,14 +149,15 @@ export class JSONInput implements Input> { } } -export function jsonInputForTargetLanguage( +export function jsonInputForTargetLanguage ( targetLanguage: string | TargetLanguage, languages?: TargetLanguage[], - handleJSONRefs = false + handleJSONRefs = false, ): JSONInput { if (typeof targetLanguage === "string") { targetLanguage = defined(languageNamed(targetLanguage, languages)); } + const compressedJSON = new CompressedJSONFromString(targetLanguage.dateTimeRecognizer, handleJSONRefs); return new JSONInput(compressedJSON); } @@ -168,6 +176,7 @@ export class InputData { input = makeInput(); this.addInput(input); } + return input; } @@ -181,43 +190,44 @@ export class InputData { input.addSourceSync(source); } - async addTypes( + async addTypes ( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ): Promise { for (const input of this._inputs) { await input.addTypes(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); } } - addTypesSync( + addTypesSync ( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ): void { for (const input of this._inputs) { input.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); } } - get needIR(): boolean { + get needIR (): boolean { return iterableSome(this._inputs, i => i.needIR); } - get needSchemaProcessing(): boolean { + get needSchemaProcessing (): boolean { return iterableSome(this._inputs, i => i.needSchemaProcessing); } - singleStringSchemaSource(): string | undefined { + singleStringSchemaSource (): string | undefined { const schemaStrings = setFilterMap(this._inputs, i => i.singleStringSchemaSource()); if (schemaStrings.size > 1) { return panic("We have more than one input with a string schema source"); } + return iterableFirst(schemaStrings); } } diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index 8fc74e6dd..ae8f4b5fd 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -18,30 +18,34 @@ import { definedMap, addHashCode, iterableFirst, - hashString + hashString, } from "collection-utils"; import { - PrimitiveTypeKind, - TransformedStringTypeKind, + type PrimitiveTypeKind, + type TransformedStringTypeKind} from "../Type"; +import { transformedStringTypeTargetTypeKindsMap, - isNumberTypeKind + isNumberTypeKind, } from "../Type"; -import { panic, assertNever, StringMap, assert, defined, parseJSON } from "../support/Support"; -import { TypeBuilder } from "../TypeBuilder"; +import { type StringMap} from "../support/Support"; +import { panic, assertNever, assert, defined, parseJSON } from "../support/Support"; +import { type TypeBuilder } from "../TypeBuilder"; import { TypeNames } from "../attributes/TypeNames"; import { makeNamesTypeAttributes, modifyTypeNames, singularizeTypeNames } from "../attributes/TypeNames"; import { - TypeAttributes, + type TypeAttributes} from "../attributes/TypeAttributes"; +import { makeTypeAttributesInferred, emptyTypeAttributes, - combineTypeAttributes + combineTypeAttributes, } from "../attributes/TypeAttributes"; -import { JSONSchema, JSONSchemaStore } from "./JSONSchemaStore"; +import { type JSONSchema} from "./JSONSchemaStore"; +import { JSONSchemaStore } from "./JSONSchemaStore"; import { messageAssert, messageError } from "../Messages"; import { StringTypes } from "../attributes/StringTypes"; -import { TypeRef } from "../TypeGraph"; +import { type TypeRef } from "../TypeGraph"; import { type RunContext } from "../Run"; import { type Input } from "./Inputs"; @@ -64,17 +68,17 @@ export enum PathElementKind { } export type PathElement = - | { kind: PathElementKind.Root } - | { kind: PathElementKind.KeyOrIndex; key: string } - | { kind: PathElementKind.Type; index: number } - | { kind: PathElementKind.Object }; + | { kind: PathElementKind.Root, } + | { key: string, kind: PathElementKind.KeyOrIndex, } + | { index: number, kind: PathElementKind.Type, } + | { kind: PathElementKind.Object, }; -function keyOrIndex(pe: PathElement): string | undefined { +function keyOrIndex (pe: PathElement): string | undefined { if (pe.kind !== PathElementKind.KeyOrIndex) return undefined; return pe.key; } -function pathElementEquals(a: PathElement, b: PathElement): boolean { +function pathElementEquals (a: PathElement, b: PathElement): boolean { if (a.kind !== b.kind) return false; switch (a.kind) { case PathElementKind.Type: @@ -86,35 +90,38 @@ function pathElementEquals(a: PathElement, b: PathElement): boolean { } } -function withRef(refOrLoc: Ref | (() => Ref) | Location): { ref: Ref }; -function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): T & { ref: Ref }; -function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): any { +function withRef (refOrLoc: Ref | (() => Ref) | Location): { ref: Ref, }; +function withRef (refOrLoc: Ref | (() => Ref) | Location, props?: T): T & { ref: Ref, }; +function withRef (refOrLoc: Ref | (() => Ref) | Location, props?: T): any { const ref = typeof refOrLoc === "function" ? refOrLoc() : refOrLoc instanceof Ref ? refOrLoc : refOrLoc.canonicalRef; return Object.assign({ ref }, props === undefined ? {} : props); } -function checkJSONSchemaObject(x: any, refOrLoc: Ref | (() => Ref)): StringMap { +function checkJSONSchemaObject (x: any, refOrLoc: Ref | (() => Ref)): StringMap { if (Array.isArray(x)) { return messageError("SchemaArrayIsInvalidSchema", withRef(refOrLoc)); } + if (x === null) { return messageError("SchemaNullIsInvalidSchema", withRef(refOrLoc)); } + if (typeof x !== "object") { return messageError("SchemaInvalidJSONSchemaType", withRef(refOrLoc, { type: typeof x })); } + return x; } -function checkJSONSchema(x: any, refOrLoc: Ref | (() => Ref)): JSONSchema { +function checkJSONSchema (x: any, refOrLoc: Ref | (() => Ref)): JSONSchema { if (typeof x === "boolean") return x; return checkJSONSchemaObject(x, refOrLoc); } const numberRegexp = new RegExp("^[0-9]+$"); -function normalizeURI(uri: string | URI): URI { +function normalizeURI (uri: string | URI): URI { // FIXME: This is overly complicated and a bit shady. The problem is // that `normalize` will URL-escape, with the result that if we want to // open the URL as a file, escaped character will thwart us. I think the @@ -123,16 +130,17 @@ function normalizeURI(uri: string | URI): URI { if (typeof uri === "string") { uri = new URI(uri); } + return new URI(URI.decode(uri.clone().normalize().toString())); } export class Ref { - static root(address: string | undefined): Ref { + static root (address: string | undefined): Ref { const uri = definedMap(address, a => new URI(a)); return new Ref(uri, []); } - private static parsePath(path: string): ReadonlyArray { + private static parsePath (path: string): readonly PathElement[] { const elements: PathElement[] = []; if (path.startsWith("/")) { @@ -146,10 +154,11 @@ export class Ref { elements.push({ kind: PathElementKind.KeyOrIndex, key: parts[i] }); } } + return elements; } - static parseURI(uri: URI, destroyURI = false): Ref { + static parseURI (uri: URI, destroyURI = false): Ref { if (!destroyURI) { uri = uri.clone(); } @@ -159,19 +168,20 @@ export class Ref { if ((uri.host() !== "" || uri.filename() !== "") && path === "") { path = "/"; } + const elements = Ref.parsePath(path); return new Ref(uri, elements); } - static parse(ref: string): Ref { + static parse (ref: string): Ref { return Ref.parseURI(new URI(ref), true); } public addressURI: URI | undefined; - constructor( + constructor ( addressURI: URI | undefined, - readonly path: ReadonlyArray + readonly path: readonly PathElement[], ) { if (addressURI !== undefined) { assert(addressURI.fragment() === "", `Ref URI with fragment is not allowed: ${addressURI.toString()}`); @@ -181,49 +191,51 @@ export class Ref { } } - get hasAddress(): boolean { + get hasAddress (): boolean { return this.addressURI !== undefined; } - get address(): string { + get address (): string { return defined(this.addressURI).toString(); } - get isRoot(): boolean { + get isRoot (): boolean { return this.path.length === 1 && this.path[0].kind === PathElementKind.Root; } - private pushElement(pe: PathElement): Ref { + private pushElement (pe: PathElement): Ref { const newPath = Array.from(this.path); newPath.push(pe); return new Ref(this.addressURI, newPath); } - push(...keys: string[]): Ref { + push (...keys: string[]): Ref { let ref: Ref = this; for (const key of keys) { ref = ref.pushElement({ kind: PathElementKind.KeyOrIndex, key }); } + return ref; } - pushObject(): Ref { + pushObject (): Ref { return this.pushElement({ kind: PathElementKind.Object }); } - pushType(index: number): Ref { + pushType (index: number): Ref { return this.pushElement({ kind: PathElementKind.Type, index }); } - resolveAgainst(base: Ref | undefined): Ref { + resolveAgainst (base: Ref | undefined): Ref { let addressURI = this.addressURI; - if (base !== undefined && base.addressURI !== undefined) { + if (base?.addressURI !== undefined) { addressURI = addressURI === undefined ? base.addressURI : addressURI.absoluteTo(base.addressURI); } + return new Ref(addressURI, this.path); } - get name(): string { + get name (): string { const path = Array.from(this.path); for (;;) { @@ -234,9 +246,11 @@ export class Ref { if (name.length > suffix.length + 1) { name = name.slice(0, name.length - suffix.length - 1); } + if (name === "") { return "Something"; } + return name; } @@ -245,6 +259,7 @@ export class Ref { if (numberRegexp.test(e.key)) { return e.key; } + break; case PathElementKind.Type: case PathElementKind.Object: @@ -255,15 +270,15 @@ export class Ref { } } - get definitionName(): string | undefined { + get definitionName (): string | undefined { const pe = arrayGetFromEnd(this.path, 2); if (pe === undefined) return undefined; if (keyOrIndex(pe) === "definitions") return keyOrIndex(defined(arrayLast(this.path))); return undefined; } - toString(): string { - function elementToString(e: PathElement): string { + toString (): string { + function elementToString (e: PathElement): string { switch (e.kind) { case PathElementKind.Root: return ""; @@ -277,16 +292,18 @@ export class Ref { return assertNever(e); } } + const address = this.addressURI === undefined ? "" : this.addressURI.toString(); return address + "#" + this.path.map(elementToString).join("/"); } - private lookup(local: any, path: ReadonlyArray, root: JSONSchema): JSONSchema { + private lookup (local: any, path: readonly PathElement[], root: JSONSchema): JSONSchema { const refMaker = () => new Ref(this.addressURI, path); const first = path[0]; if (first === undefined) { return checkJSONSchema(local, refMaker); } + const rest = path.slice(1); switch (first.kind) { case PathElementKind.Root: @@ -297,46 +314,52 @@ export class Ref { if (!/^\d+$/.test(key)) { return messageError("SchemaCannotIndexArrayWithNonNumber", withRef(refMaker, { actual: key })); } + const index = parseInt(first.key, 10); if (index >= local.length) { return messageError("SchemaIndexNotInArray", withRef(refMaker, { index })); } + return this.lookup(local[index], rest, root); } else { if (!hasOwnProperty(local, key)) { return messageError("SchemaKeyNotInObject", withRef(refMaker, { key })); } + return this.lookup(checkJSONSchemaObject(local, refMaker)[first.key], rest, root); } + case PathElementKind.Type: - return panic('Cannot look up path that indexes "type"'); + return panic("Cannot look up path that indexes \"type\""); case PathElementKind.Object: - return panic('Cannot look up path that indexes "object"'); + return panic("Cannot look up path that indexes \"object\""); default: return assertNever(first); } } - lookupRef(root: JSONSchema): JSONSchema { + lookupRef (root: JSONSchema): JSONSchema { return this.lookup(root, this.path, root); } - equals(other: any): boolean { + equals (other: any): boolean { if (!(other instanceof Ref)) return false; if (this.addressURI !== undefined && other.addressURI !== undefined) { if (!this.addressURI.equals(other.addressURI)) return false; } else { - if ((this.addressURI === undefined) !== (other.addressURI === undefined)) return false; + if (this.addressURI === undefined !== (other.addressURI === undefined)) return false; } + const l = this.path.length; if (l !== other.path.length) return false; for (let i = 0; i < l; i++) { if (!pathElementEquals(this.path[i], other.path[i])) return false; } + return true; } - hashCode(): number { + hashCode (): number { let acc = hashCodeOf(definedMap(this.addressURI, u => u.toString())); for (const pe of this.path) { acc = addHashCode(acc, pe.kind); @@ -351,84 +374,94 @@ export class Ref { break; } } + return acc; } } class Location { public readonly canonicalRef: Ref; + public readonly virtualRef: Ref; - constructor( + constructor ( canonicalRef: Ref, virtualRef?: Ref, - readonly haveID: boolean = false + readonly haveID: boolean = false, ) { this.canonicalRef = canonicalRef; this.virtualRef = virtualRef !== undefined ? virtualRef : canonicalRef; } - updateWithID(id: any) { + updateWithID (id: any) { if (typeof id !== "string") return this; const parsed = Ref.parse(id); const virtual = this.haveID ? parsed.resolveAgainst(this.virtualRef) : parsed; if (!this.haveID) { messageAssert(virtual.hasAddress, "SchemaIDMustHaveAddress", withRef(this, { id })); } + return new Location(this.canonicalRef, virtual, true); } - push(...keys: string[]): Location { + push (...keys: string[]): Location { return new Location(this.canonicalRef.push(...keys), this.virtualRef.push(...keys), this.haveID); } - pushObject(): Location { + pushObject (): Location { return new Location(this.canonicalRef.pushObject(), this.virtualRef.pushObject(), this.haveID); } - pushType(index: number): Location { + pushType (index: number): Location { return new Location(this.canonicalRef.pushType(index), this.virtualRef.pushType(index), this.haveID); } - toString(): string { + toString (): string { return `${this.virtualRef.toString()} (${this.canonicalRef.toString()})`; } } class Canonizer { private readonly _map = new EqualityMap(); + private readonly _schemaAddressesAdded = new Set(); - constructor(private readonly _ctx: RunContext) {} + constructor (private readonly _ctx: RunContext) {} - private addIDs(schema: any, loc: Location) { + private addIDs (schema: any, loc: Location) { if (schema === null) return; if (Array.isArray(schema)) { for (let i = 0; i < schema.length; i++) { this.addIDs(schema[i], loc.push(i.toString())); } + return; } + if (typeof schema !== "object") { return; } + const locWithoutID = loc; - const maybeID = schema["$id"]; + const maybeID = schema.$id; if (typeof maybeID === "string") { loc = loc.updateWithID(maybeID); } + if (loc.haveID) { if (this._ctx.debugPrintSchemaResolving) { console.log(`adding mapping ${loc.toString()}`); } + this._map.set(loc.virtualRef, locWithoutID); } + for (const property of Object.getOwnPropertyNames(schema)) { this.addIDs(schema[property], loc.push(property)); } } - addSchema(schema: any, address: string): boolean { + addSchema (schema: any, address: string): boolean { if (this._schemaAddressesAdded.has(address)) return false; this.addIDs(schema, new Location(Ref.root(address), Ref.root(undefined))); @@ -437,19 +470,20 @@ class Canonizer { } // Returns: Canonical ref - canonize(base: Location, ref: Ref): Location { + canonize (base: Location, ref: Ref): Location { const virtual = ref.resolveAgainst(base.virtualRef); const loc = this._map.get(virtual); if (loc !== undefined) { return loc; } + const canonicalRef = virtual.addressURI === undefined ? new Ref(base.canonicalRef.addressURI, virtual.path) : virtual; return new Location(canonicalRef, new Ref(undefined, virtual.path)); } } -function checkTypeList(typeOrTypes: any, loc: Location): ReadonlySet { +function checkTypeList (typeOrTypes: any, loc: Location): ReadonlySet { let set: Set; if (typeof typeOrTypes === "string") { set = new Set([typeOrTypes]); @@ -459,30 +493,36 @@ function checkTypeList(typeOrTypes: any, loc: Location): ReadonlySet { if (typeof t !== "string") { return messageError("SchemaTypeElementMustBeString", withRef(loc, { element: t })); } + arr.push(t); } + set = new Set(arr); } else { return messageError("SchemaTypeMustBeStringOrStringArray", withRef(loc, { actual: typeOrTypes })); } + messageAssert(set.size > 0, "SchemaNoTypeSpecified", withRef(loc)); const validTypes = ["null", "boolean", "object", "array", "number", "string", "integer"]; - const maybeInvalid = iterableFind(set, s => validTypes.indexOf(s) < 0); + const maybeInvalid = iterableFind(set, s => !validTypes.includes(s)); if (maybeInvalid !== undefined) { return messageError("SchemaInvalidType", withRef(loc, { type: maybeInvalid })); } + return set; } -function checkRequiredArray(arr: any, loc: Location): string[] { +function checkRequiredArray (arr: any, loc: Location): string[] { if (!Array.isArray(arr)) { return messageError("SchemaRequiredMustBeStringOrStringArray", withRef(loc, { actual: arr })); } + for (const e of arr) { if (typeof e !== "string") { return messageError("SchemaRequiredElementMustBeString", withRef(loc, { element: e })); } } + return arr; } @@ -493,20 +533,20 @@ export const schemaTypeDict = { integer: true, number: true, array: true, - object: true + object: true, }; export type JSONSchemaType = keyof typeof schemaTypeDict; const schemaTypes = Object.getOwnPropertyNames(schemaTypeDict) as JSONSchemaType[]; -export type JSONSchemaAttributes = { - forType?: TypeAttributes; - forUnion?: TypeAttributes; - forObject?: TypeAttributes; +export interface JSONSchemaAttributes { + forCases?: TypeAttributes[]; forNumber?: TypeAttributes; + forObject?: TypeAttributes; forString?: TypeAttributes; - forCases?: TypeAttributes[]; -}; + forType?: TypeAttributes; + forUnion?: TypeAttributes; +} export type JSONSchemaAttributeProducer = ( schema: JSONSchema, canonicalRef: Ref, @@ -514,16 +554,16 @@ export type JSONSchemaAttributeProducer = ( unionCases: JSONSchema[] | undefined ) => JSONSchemaAttributes | undefined; -function typeKindForJSONSchemaFormat(format: string): TransformedStringTypeKind | undefined { +function typeKindForJSONSchemaFormat (format: string): TransformedStringTypeKind | undefined { const target = iterableFind( transformedStringTypeTargetTypeKindsMap, - ([_, { jsonSchema }]) => jsonSchema === format + ([_, { jsonSchema }]) => jsonSchema === format, ); if (target === undefined) return undefined; return target[0] as TransformedStringTypeKind; } -function schemaFetchError(base: Location | undefined, address: string): never { +function schemaFetchError (base: Location | undefined, address: string): never { if (base === undefined) { return messageError("SchemaFetchErrorTopLevel", { address }); } else { @@ -532,16 +572,16 @@ function schemaFetchError(base: Location | undefined, address: string): never { } class Resolver { - constructor( + constructor ( private readonly _ctx: RunContext, private readonly _store: JSONSchemaStore, - private readonly _canonizer: Canonizer + private readonly _canonizer: Canonizer, ) {} - private async tryResolveVirtualRef( + private async tryResolveVirtualRef ( fetchBase: Location, lookupBase: Location, - virtualRef: Ref + virtualRef: Ref, ): Promise<[JSONSchema | undefined, Location]> { let didAdd = false; // If we are resolving into a schema file that we haven't seen yet then @@ -571,15 +611,16 @@ class Resolver { lookupLoc = new Location( new Ref(loc.canonicalRef.addressURI, lookupLoc.canonicalRef.path), lookupLoc.virtualRef, - lookupLoc.haveID + lookupLoc.haveID, ); } + return [lookupLoc.canonicalRef.lookupRef(schema), lookupLoc]; } } } - async resolveVirtualRef(base: Location, virtualRef: Ref): Promise<[JSONSchema, Location]> { + async resolveVirtualRef (base: Location, virtualRef: Ref): Promise<[JSONSchema, Location]> { if (this._ctx.debugPrintSchemaResolving) { console.log(`resolving ${virtualRef.toString()} relative to ${base.toString()}`); } @@ -592,13 +633,14 @@ class Resolver { if (this._ctx.debugPrintSchemaResolving) { console.log(`resolved to ${result[1].toString()}`); } + return [schema, result[1]]; } const altBase = new Location( base.canonicalRef, new Ref(base.canonicalRef.addressURI, base.virtualRef.path), - base.haveID + base.haveID, ); result = await this.tryResolveVirtualRef(altBase, base, virtualRef); schema = result[0]; @@ -606,40 +648,42 @@ class Resolver { if (this._ctx.debugPrintSchemaResolving) { console.log(`resolved to ${result[1].toString()}`); } + return [schema, result[1]]; } return schemaFetchError(base, virtualRef.address); } - async resolveTopLevelRef(ref: Ref): Promise<[JSONSchema, Location]> { + async resolveTopLevelRef (ref: Ref): Promise<[JSONSchema, Location]> { return await this.resolveVirtualRef(new Location(new Ref(ref.addressURI, [])), new Ref(undefined, ref.path)); } } -async function addTypesInSchema( +async function addTypesInSchema ( resolver: Resolver, typeBuilder: TypeBuilder, references: ReadonlyMap, - attributeProducers: JSONSchemaAttributeProducer[] + attributeProducers: JSONSchemaAttributeProducer[], ): Promise { let typeForCanonicalRef = new EqualityMap(); - function setTypeForLocation(loc: Location, t: TypeRef): void { + function setTypeForLocation (loc: Location, t: TypeRef): void { const maybeRef = typeForCanonicalRef.get(loc.canonicalRef); if (maybeRef !== undefined) { assert(maybeRef === t, "Trying to set path again to different type"); } + typeForCanonicalRef.set(loc.canonicalRef, t); } - async function makeObject( + async function makeObject ( loc: Location, attributes: TypeAttributes, properties: StringMap, requiredArray: string[], additionalProperties: any, - sortKey: (k: string) => number | string = (k: string) => k.toLowerCase() + sortKey: (k: string) => number | string = (k: string) => k.toLowerCase(), ): Promise { const required = new Set(requiredArray); const propertiesMap = mapSortBy(mapFromObject(properties), (_, k) => sortKey(k)); @@ -648,7 +692,7 @@ async function addTypesInSchema( const t = await toType( checkJSONSchema(propSchema, propLoc.canonicalRef), propLoc, - makeNamesTypeAttributes(propName, true) + makeNamesTypeAttributes(propName, true), ); const isOptional = !required.has(propName); return typeBuilder.makeClassProperty(t, isOptional); @@ -663,9 +707,10 @@ async function addTypesInSchema( additionalPropertiesType = await toType( checkJSONSchema(additionalProperties, additionalLoc.canonicalRef), additionalLoc, - singularizeTypeNames(attributes) + singularizeTypeNames(attributes), ); } + const additionalRequired = setSubtract(required, props.keys()); if (additionalRequired.size > 0) { const t = additionalPropertiesType; @@ -674,22 +719,24 @@ async function addTypesInSchema( } const additionalProps = mapFromIterable(additionalRequired, _name => - typeBuilder.makeClassProperty(t, false) + typeBuilder.makeClassProperty(t, false), ); mapMergeInto(props, additionalProps); } + return typeBuilder.getUniqueObjectType(attributes, props, additionalPropertiesType); } - async function convertToType(schema: StringMap, loc: Location, typeAttributes: TypeAttributes): Promise { + async function convertToType (schema: StringMap, loc: Location, typeAttributes: TypeAttributes): Promise { const enumArray = Array.isArray(schema.enum) ? schema.enum : undefined; const isConst = schema.const !== undefined; const typeSet = definedMap(schema.type, t => checkTypeList(t, loc)); - function isTypeIncluded(name: JSONSchemaType): boolean { + function isTypeIncluded (name: JSONSchemaType): boolean { if (typeSet !== undefined && !typeSet.has(name)) { return false; } + if (enumArray !== undefined) { let predicate: (x: any) => boolean; switch (name) { @@ -706,18 +753,20 @@ async function addTypesInSchema( return enumArray.find(predicate) !== undefined; } + if (isConst) { return name === (schema.type ?? typeof schema.const); } + return true; } const includedTypes = setFilter(schemaTypes, isTypeIncluded); let producedAttributesForNoCases: JSONSchemaAttributes[] | undefined = undefined; - function forEachProducedAttribute( + function forEachProducedAttribute ( cases: JSONSchema[] | undefined, - f: (attributes: JSONSchemaAttributes) => void + f: (attributes: JSONSchemaAttributes) => void, ): void { let attributes: JSONSchemaAttributes[]; if (cases === undefined && producedAttributesForNoCases !== undefined) { @@ -729,17 +778,19 @@ async function addTypesInSchema( if (newAttributes === undefined) continue; attributes.push(newAttributes); } + if (cases === undefined) { producedAttributesForNoCases = attributes; } } + for (const a of attributes) { f(a); } } - function combineProducedAttributes( - f: (attributes: JSONSchemaAttributes) => TypeAttributes | undefined + function combineProducedAttributes ( + f: (attributes: JSONSchemaAttributes) => TypeAttributes | undefined, ): TypeAttributes { let result = emptyTypeAttributes; forEachProducedAttribute(undefined, attr => { @@ -750,7 +801,7 @@ async function addTypesInSchema( return result; } - function makeAttributes(attributes: TypeAttributes): TypeAttributes { + function makeAttributes (attributes: TypeAttributes): TypeAttributes { if (schema.oneOf === undefined) { attributes = combineTypeAttributes( "union", @@ -758,17 +809,19 @@ async function addTypesInSchema( combineProducedAttributes(({ forType, forUnion, forCases }) => { assert( forUnion === undefined && forCases === undefined, - "We can't have attributes for unions and cases if we don't have a union" + "We can't have attributes for unions and cases if we don't have a union", ); return forType; - }) + }), ); } + return modifyTypeNames(attributes, maybeTypeNames => { const typeNames = defined(maybeTypeNames); if (!typeNames.areInferred) { return typeNames; } + let title = schema.title; if (typeof title !== "string") { title = loc.canonicalRef.definitionName; @@ -785,7 +838,7 @@ async function addTypesInSchema( typeAttributes = makeAttributes(typeAttributes); const inferredAttributes = makeTypeAttributesInferred(typeAttributes); - function makeStringType(attributes: TypeAttributes): TypeRef { + function makeStringType (attributes: TypeAttributes): TypeRef { const kind = typeKindForJSONSchemaFormat(schema.format); if (kind === undefined) { return typeBuilder.getStringType(attributes, StringTypes.unrestricted); @@ -794,7 +847,7 @@ async function addTypesInSchema( } } - async function makeArrayType(): Promise { + async function makeArrayType (): Promise { const singularAttributes = singularizeTypeNames(typeAttributes); const items = schema.items; let itemType: TypeRef; @@ -813,11 +866,12 @@ async function addTypesInSchema( } else { itemType = typeBuilder.getPrimitiveType("any"); } + typeBuilder.addAttributes(itemType, singularAttributes); return typeBuilder.getArrayType(emptyTypeAttributes, itemType); } - async function makeObjectType(): Promise { + async function makeObjectType (): Promise { let required: string[]; if (schema.required === undefined || typeof schema.required === "boolean") { required = []; @@ -834,7 +888,7 @@ async function addTypesInSchema( // In Schema Draft 3, `required` is `true` on a property that's required. for (const p of Object.getOwnPropertyNames(properties)) { - if (properties[p].required === true && required.indexOf(p) < 0) { + if (properties[p].required === true && !required.includes(p)) { required.push(p); } } @@ -853,7 +907,7 @@ async function addTypesInSchema( const objectAttributes = combineTypeAttributes( "union", inferredAttributes, - combineProducedAttributes(({ forObject }) => forObject) + combineProducedAttributes(({ forObject }) => forObject), ); const order = schema.quicktypePropertyOrder ? schema.quicktypePropertyOrder : []; const orderKey = (propertyName: string) => { @@ -866,18 +920,19 @@ async function addTypesInSchema( return await makeObject(loc, objectAttributes, properties, required, additionalProperties, orderKey); } - async function makeTypesFromCases(cases: any, kind: string): Promise { + async function makeTypesFromCases (cases: any, kind: string): Promise { const kindLoc = loc.push(kind); if (!Array.isArray(cases)) { return messageError("SchemaSetOperationCasesIsNotArray", withRef(kindLoc, { operation: kind, cases })); } + // FIXME: This cast shouldn't be necessary, but TypeScript forces our hand. return await arrayMapSync(cases, async (t, index) => { const caseLoc = kindLoc.push(index.toString()); return await toType( checkJSONSchema(t, caseLoc.canonicalRef), caseLoc, - makeTypeAttributesInferred(typeAttributes) + makeTypeAttributesInferred(typeAttributes), ); }); } @@ -885,7 +940,7 @@ async function addTypesInSchema( const intersectionType = typeBuilder.getUniqueIntersectionType(typeAttributes, undefined); setTypeForLocation(loc, intersectionType); - async function convertOneOrAnyOf(cases: any, kind: string): Promise { + async function convertOneOrAnyOf (cases: any, kind: string): Promise { const typeRefs = await makeTypesFromCases(cases, kind); let unionAttributes = makeTypeAttributesInferred(typeAttributes); if (kind === "oneOf") { @@ -893,13 +948,15 @@ async function addTypesInSchema( if (forType !== undefined) { typeBuilder.addAttributes(intersectionType, forType); } + if (forUnion !== undefined) { unionAttributes = combineTypeAttributes("union", unionAttributes, forUnion); } + if (forCases !== undefined) { assert( forCases.length === typeRefs.length, - "Number of case attributes doesn't match number of cases" + "Number of case attributes doesn't match number of cases", ); for (let i = 0; i < typeRefs.length; i++) { typeBuilder.addAttributes(typeRefs[i], forCases[i]); @@ -907,6 +964,7 @@ async function addTypesInSchema( } }); } + const unionType = typeBuilder.getUniqueUnionType(unionAttributes, undefined); typeBuilder.setSetOperationMembers(unionType, new Set(typeRefs)); return unionType; @@ -938,8 +996,8 @@ async function addTypesInSchema( ["null", "null"], ["number", "double"], ["integer", "integer"], - ["boolean", "bool"] - ] as [JSONSchemaType, PrimitiveTypeKind][]) { + ["boolean", "bool"], + ] as Array<[JSONSchemaType, PrimitiveTypeKind]>) { if (!includedTypes.has(name)) continue; const attributes = isNumberTypeKind(kind) ? numberAttributes : undefined; @@ -949,7 +1007,7 @@ async function addTypesInSchema( const stringAttributes = combineTypeAttributes( "union", inferredAttributes, - combineProducedAttributes(({ forString }) => forString) + combineProducedAttributes(({ forString }) => forString), ); if (needStringEnum || isConst) { @@ -964,6 +1022,7 @@ async function addTypesInSchema( if (includeArray) { unionTypes.push(await makeArrayType()); } + if (includeObject) { unionTypes.push(await makeObjectType()); } @@ -975,6 +1034,7 @@ async function addTypesInSchema( if (typeof schema.$ref !== "string") { return messageError("SchemaRefMustBeString", withRef(loc, { actual: typeof schema.$ref })); } + const virtualRef = Ref.parse(schema.$ref); const [target, newLoc] = await resolver.resolveVirtualRef(loc, virtualRef); const attributes = modifyTypeNames(typeAttributes, tn => { @@ -985,11 +1045,13 @@ async function addTypesInSchema( } if (schema.allOf !== undefined) { - types.push(...(await makeTypesFromCases(schema.allOf, "allOf"))); + types.push(...await makeTypesFromCases(schema.allOf, "allOf")); } + if (schema.oneOf !== undefined) { types.push(await convertOneOrAnyOf(schema.oneOf, "oneOf")); } + if (schema.anyOf !== undefined) { types.push(await convertOneOrAnyOf(schema.anyOf, "anyOf")); } @@ -998,7 +1060,7 @@ async function addTypesInSchema( return intersectionType; } - async function toType(schema: JSONSchema, loc: Location, typeAttributes: TypeAttributes): Promise { + async function toType (schema: JSONSchema, loc: Location, typeAttributes: TypeAttributes): Promise { const maybeType = typeForCanonicalRef.get(loc.canonicalRef); if (maybeType !== undefined) { return maybeType; @@ -1011,7 +1073,7 @@ async function addTypesInSchema( messageAssert(schema === true, "SchemaFalseNotSupported", withRef(loc)); result = typeBuilder.getPrimitiveType("any"); } else { - loc = loc.updateWithID(schema["$id"]); + loc = loc.updateWithID(schema.$id); result = await convertToType(schema, loc, typeAttributes); } @@ -1026,7 +1088,7 @@ async function addTypesInSchema( } } -function removeExtension(fn: string): string { +function removeExtension (fn: string): string { const lower = fn.toLowerCase(); const extensions = [".json", ".schema"]; for (const ext of extensions) { @@ -1037,10 +1099,11 @@ function removeExtension(fn: string): string { } } } + return fn; } -function nameFromURI(uri: URI): string | undefined { +function nameFromURI (uri: URI): string | undefined { const fragment = uri.fragment(); if (fragment !== "") { const components = fragment.split("/"); @@ -1048,27 +1111,31 @@ function nameFromURI(uri: URI): string | undefined { if (components[len - 1] !== "") { return removeExtension(components[len - 1]); } + if (len > 1 && components[len - 2] !== "") { return removeExtension(components[len - 2]); } } + const filename = uri.filename(); if (filename !== "") { return removeExtension(filename); } + return messageError("DriverCannotInferNameForSchema", { uri: uri.toString() }); } -async function refsInSchemaForURI( +async function refsInSchemaForURI ( resolver: Resolver, uri: URI, - defaultName: string + defaultName: string, ): Promise | [string, Ref]> { const fragment = uri.fragment(); let propertiesAreTypes = fragment.endsWith("/"); if (propertiesAreTypes) { uri = uri.clone().fragment(fragment.slice(0, -1)); } + const ref = Ref.parseURI(uri); if (ref.isRoot) { propertiesAreTypes = false; @@ -1080,6 +1147,7 @@ async function refsInSchemaForURI( if (typeof schema !== "object") { return messageError("SchemaCannotGetTypesFromBoolean", { ref: ref.toString() }); } + return mapMap(mapFromObject(schema), (_, name) => ref.push(name)); } else { let name: string; @@ -1089,54 +1157,59 @@ async function refsInSchemaForURI( const maybeName = nameFromURI(uri); name = maybeName !== undefined ? maybeName : defaultName; } + return [name, ref]; } } class InputJSONSchemaStore extends JSONSchemaStore { - constructor( + constructor ( private readonly _inputs: Map, - private readonly _delegate?: JSONSchemaStore + private readonly _delegate?: JSONSchemaStore, ) { super(); } - async fetch(address: string): Promise { + async fetch (address: string): Promise { const maybeInput = this._inputs.get(address); if (maybeInput !== undefined) { return checkJSONSchema(parseJSON(maybeInput, "JSON Schema", address), () => Ref.root(address)); } + if (this._delegate === undefined) { return panic(`Schema URI ${address} requested, but no store given`); } + return await this._delegate.fetch(address); } } export interface JSONSchemaSourceData { + isConverted?: boolean; name: string; - uris?: string[]; schema?: string; - isConverted?: boolean; + uris?: string[]; } export class JSONSchemaInput implements Input { readonly kind: string = "schema"; + readonly needSchemaProcessing: boolean = true; private readonly _attributeProducers: JSONSchemaAttributeProducer[]; private readonly _schemaInputs: Map = new Map(); - private _schemaSources: [URI, JSONSchemaSourceData][] = []; + + private _schemaSources: Array<[URI, JSONSchemaSourceData]> = []; private readonly _topLevels: Map = new Map(); private _needIR = false; - constructor( + constructor ( private _schemaStore: JSONSchemaStore | undefined, additionalAttributeProducers: JSONSchemaAttributeProducer[] = [], - private readonly _additionalSchemaAddresses: ReadonlyArray = [] + private readonly _additionalSchemaAddresses: readonly string[] = [], ) { this._attributeProducers = [ descriptionAttributeProducer, @@ -1145,19 +1218,19 @@ export class JSONSchemaInput implements Input { uriSchemaAttributesProducer, minMaxAttributeProducer, minMaxLengthAttributeProducer, - patternAttributeProducer + patternAttributeProducer, ].concat(additionalAttributeProducers); } - get needIR(): boolean { + get needIR (): boolean { return this._needIR; } - addTopLevel(name: string, ref: Ref): void { + addTopLevel (name: string, ref: Ref): void { this._topLevels.set(name, ref); } - async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise { + async addTypes (ctx: RunContext, typeBuilder: TypeBuilder): Promise { if (this._schemaSources.length === 0) return; let maybeSchemaStore = this._schemaStore; @@ -1168,6 +1241,7 @@ export class JSONSchemaInput implements Input { } else { maybeSchemaStore = this._schemaStore = new InputJSONSchemaStore(this._schemaInputs, maybeSchemaStore); } + const schemaStore = maybeSchemaStore; const canonizer = new Canonizer(ctx); @@ -1176,6 +1250,7 @@ export class JSONSchemaInput implements Input { if (schema === undefined) { return messageError("SchemaFetchErrorAdditional", { address }); } + canonizer.addSchema(schema, address); } @@ -1192,6 +1267,7 @@ export class JSONSchemaInput implements Input { } else { name = refs[0]; } + this.addTopLevel(name, refs[1]); } else { for (const [refName, ref] of refs) { @@ -1203,15 +1279,15 @@ export class JSONSchemaInput implements Input { await addTypesInSchema(resolver, typeBuilder, this._topLevels, this._attributeProducers); } - addTypesSync(): void { + addTypesSync (): void { return panic("addTypesSync not supported in JSONSchemaInput"); } - async addSource(schemaSource: JSONSchemaSourceData): Promise { - return this.addSourceSync(schemaSource); + async addSource (schemaSource: JSONSchemaSourceData): Promise { + this.addSourceSync(schemaSource); } - addSourceSync(schemaSource: JSONSchemaSourceData): void { + addSourceSync (schemaSource: JSONSchemaSourceData): void { const { name, uris, schema, isConverted } = schemaSource; if (isConverted !== true) { @@ -1227,6 +1303,7 @@ export class JSONSchemaInput implements Input { if (normalizedURI.clone().hash("").toString() === "") { normalizedURI.path(name); } + return normalizedURI; }); } @@ -1243,8 +1320,10 @@ export class JSONSchemaInput implements Input { if (suffix > 0) { uri.path(`${path}-${suffix}`); } + suffix++; } while (this._schemaInputs.has(uri.toString())); + this._schemaInputs.set(uri.toString(), schema); normalizedURIs[i] = uri.hash(normalizedURI.hash()); } @@ -1256,14 +1335,16 @@ export class JSONSchemaInput implements Input { } } - singleStringSchemaSource(): string | undefined { + singleStringSchemaSource (): string | undefined { if (!this._schemaSources.every(([_, { schema }]) => typeof schema === "string")) { return undefined; } + const set = new Set(this._schemaSources.map(([_, { schema }]) => schema as string)); if (set.size === 1) { return defined(iterableFirst(set)); } + return undefined; } } diff --git a/packages/quicktype-core/src/input/JSONSchemaStore.ts b/packages/quicktype-core/src/input/JSONSchemaStore.ts index dc7ef9aea..32f886e3e 100644 --- a/packages/quicktype-core/src/input/JSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/JSONSchemaStore.ts @@ -1,38 +1,45 @@ -import { StringMap, assert } from "../support/Support"; +import { type StringMap} from "../support/Support"; +import { assert } from "../support/Support"; export type JSONSchema = StringMap | boolean; export abstract class JSONSchemaStore { private readonly _schemas = new Map(); - private add(address: string, schema: JSONSchema): void { + private add (address: string, schema: JSONSchema): void { assert(!this._schemas.has(address), "Cannot set a schema for an address twice"); this._schemas.set(address, schema); } // FIXME: Remove the undefined option - abstract fetch(_address: string): Promise; + abstract fetch (_address: string): Promise; - async get(address: string, debugPrint: boolean): Promise { + async get (address: string, debugPrint: boolean): Promise { let schema = this._schemas.get(address); if (schema !== undefined) { return schema; } + if (debugPrint) { console.log(`trying to fetch ${address}`); } + try { schema = await this.fetch(address); } catch {} + if (schema === undefined) { if (debugPrint) { console.log(`couldn't fetch ${address}`); } + return undefined; } + if (debugPrint) { console.log(`successully fetched ${address}`); } + this.add(address, schema); return schema; } diff --git a/packages/quicktype-core/src/input/PostmanCollection.ts b/packages/quicktype-core/src/input/PostmanCollection.ts index d5de09947..7d4a4b7b2 100644 --- a/packages/quicktype-core/src/input/PostmanCollection.ts +++ b/packages/quicktype-core/src/input/PostmanCollection.ts @@ -1,7 +1,7 @@ import { parseJSON } from "../support/Support"; -import { JSONSourceData } from "./Inputs"; +import { type JSONSourceData } from "./Inputs"; -function isValidJSON(s: string): boolean { +function isValidJSON (s: string): boolean { try { JSON.parse(s); return true; @@ -10,23 +10,25 @@ function isValidJSON(s: string): boolean { } } -export function sourcesFromPostmanCollection( +export function sourcesFromPostmanCollection ( collectionJSON: string, - collectionJSONAddress?: string -): { sources: JSONSourceData[]; description: string | undefined } { - const sources: JSONSourceData[] = []; + collectionJSONAddress?: string, +): { description: string | undefined, sources: Array>, } { + const sources: Array> = []; const descriptions: string[] = []; - function processCollection(c: any): void { + function processCollection (c: any): void { if (typeof c !== "object") return; if (Array.isArray(c.item)) { for (const item of c.item) { processCollection(item); } + if (typeof c.info === "object" && typeof c.info.description === "string") { descriptions.push(c.info.description); } } + if (typeof c.name === "string" && Array.isArray(c.response)) { const samples: string[] = []; for (const r of c.response) { @@ -34,6 +36,7 @@ export function sourcesFromPostmanCollection( samples.push(r.body); } } + if (samples.length > 0) { const source: JSONSourceData = { name: c.name, samples }; const sourceDescription = [c.name]; diff --git a/packages/quicktype-core/src/input/io/NodeIO.ts b/packages/quicktype-core/src/input/io/NodeIO.ts index e7cfe588e..bb6d3f8f9 100644 --- a/packages/quicktype-core/src/input/io/NodeIO.ts +++ b/packages/quicktype-core/src/input/io/NodeIO.ts @@ -1,5 +1,5 @@ import * as fs from "fs"; -import { Readable } from "readable-stream"; +import { type Readable } from "readable-stream"; import { isNode } from "browser-or-node"; import { getStream } from "./get-stream"; import { defined, exceptionToString } from "@glideapps/ts-necessities"; @@ -12,7 +12,7 @@ interface HttpHeaders { [key: string]: string; } -function parseHeaders(httpHeaders?: string[]): HttpHeaders { +function parseHeaders (httpHeaders?: string[]): HttpHeaders { if (!Array.isArray(httpHeaders)) { return {}; } @@ -34,11 +34,11 @@ function parseHeaders(httpHeaders?: string[]): HttpHeaders { }, {} as HttpHeaders); } -export async function readableFromFileOrURL(fileOrURL: string, httpHeaders?: string[]): Promise { +export async function readableFromFileOrURL (fileOrURL: string, httpHeaders?: string[]): Promise { try { if (isURL(fileOrURL)) { const response = await fetch(fileOrURL, { - headers: parseHeaders(httpHeaders) + headers: parseHeaders(httpHeaders), }); return defined(response.body) as unknown as Readable; } else if (isNode) { @@ -46,6 +46,7 @@ export async function readableFromFileOrURL(fileOrURL: string, httpHeaders?: str // Cast node readable to isomorphic readable from readable-stream return process.stdin as unknown as Readable; } + const filePath = fs.lstatSync(fileOrURL).isSymbolicLink() ? fs.readlinkSync(fileOrURL) : fileOrURL; if (fs.existsSync(filePath)) { // Cast node readable to isomorphic readable from readable-stream @@ -55,10 +56,11 @@ export async function readableFromFileOrURL(fileOrURL: string, httpHeaders?: str } catch (e) { return messageError("MiscReadError", { fileOrURL, message: exceptionToString(e) }); } + return messageError("DriverInputFileDoesNotExist", { filename: fileOrURL }); } -export async function readFromFileOrURL(fileOrURL: string, httpHeaders?: string[]): Promise { +export async function readFromFileOrURL (fileOrURL: string, httpHeaders?: string[]): Promise { const readable = await readableFromFileOrURL(fileOrURL, httpHeaders); try { return await getStream(readable); diff --git a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts index 19cd6ec30..f1cb10861 100644 --- a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts +++ b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts @@ -1,7 +1,7 @@ -import { Options } from "."; +import { type Options } from "."; import { PassThrough } from "readable-stream"; -export default function bufferStream(opts: Options) { +export default function bufferStream (opts: Options) { opts = Object.assign({}, opts); const array = opts.array; @@ -22,7 +22,7 @@ export default function bufferStream(opts: Options) { let len = 0; const ret: any[] = []; const stream = new PassThrough({ - objectMode + objectMode, }) as any; if (encoding) { diff --git a/packages/quicktype-core/src/input/io/get-stream/index.ts b/packages/quicktype-core/src/input/io/get-stream/index.ts index 9036e7c89..98ae97240 100644 --- a/packages/quicktype-core/src/input/io/get-stream/index.ts +++ b/packages/quicktype-core/src/input/io/get-stream/index.ts @@ -1,15 +1,15 @@ -import { Readable } from "readable-stream"; +import { type Readable } from "readable-stream"; import bufferStream from "./buffer-stream"; export interface Options { - maxBuffer?: number; array?: boolean; encoding?: string; + maxBuffer?: number; } -export function getStream(inputStream: Readable, opts: Options = {}) { +export async function getStream (inputStream: Readable, opts: Options = {}) { if (!inputStream) { - return Promise.reject(new Error("Expected a stream")); + return await Promise.reject(new Error("Expected a stream")); } opts = Object.assign({ maxBuffer: Infinity }, opts); @@ -50,13 +50,13 @@ export function getStream(inputStream: Readable, opts: Options = {}) { p.then(clean, clean); - return p.then(() => stream.getBufferedValue()); + return await p.then(() => stream.getBufferedValue()); } -export function buffer(stream: Readable, opts: Options = {}) { +export function buffer (stream: Readable, opts: Options = {}) { getStream(stream, Object.assign({}, opts, { encoding: "buffer" })); } -export function array(stream: Readable, opts: Options = {}) { +export function array (stream: Readable, opts: Options = {}) { getStream(stream, Object.assign({}, opts, { array: true })); } diff --git a/packages/quicktype-core/src/language/All.ts b/packages/quicktype-core/src/language/All.ts index 19313870a..91cb4b1a0 100644 --- a/packages/quicktype-core/src/language/All.ts +++ b/packages/quicktype-core/src/language/All.ts @@ -1,6 +1,6 @@ import { iterableFind } from "collection-utils"; -import { TargetLanguage } from "../TargetLanguage"; +import { type TargetLanguage } from "../TargetLanguage"; import { CSharpTargetLanguage } from "./CSharp"; import { GoTargetLanguage } from "./Golang"; @@ -54,16 +54,17 @@ export const all: TargetLanguage[] = [ new HaskellTargetLanguage(), new TypeScriptZodTargetLanguage(), new TypeScriptEffectSchemaTargetLanguage(), - new PhpTargetLanguage() + new PhpTargetLanguage(), ]; -export function languageNamed(name: string, targetLanguages?: TargetLanguage[]): TargetLanguage | undefined { +export function languageNamed (name: string, targetLanguages?: TargetLanguage[]): TargetLanguage | undefined { if (targetLanguages === undefined) { targetLanguages = all; } + const maybeTargetLanguage = iterableFind( targetLanguages, - l => l.names.indexOf(name) >= 0 || l.displayName === name + l => l.names.includes(name) || l.displayName === name, ); if (maybeTargetLanguage !== undefined) return maybeTargetLanguage; return iterableFind(targetLanguages, l => l.extension === name); diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index 8dd1990b2..c103d3ffe 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -23,23 +23,28 @@ /* Imports */ import { TargetLanguage } from "../TargetLanguage"; -import { Type, TypeKind, ClassType, ArrayType, MapType, EnumType, UnionType } from "../Type"; +import { type Type, type TypeKind} from "../Type"; +import { ClassType, ArrayType, MapType, EnumType, UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { NameStyle, Name, Namer, funPrefixNamer } from "../Naming"; -import { Sourcelike } from "../Source"; +import { type NameStyle, type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Sourcelike } from "../Source"; +import { + type NamingStyle} from "../support/Strings"; import { allUpperWordStyle, legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit, - NamingStyle, - makeNameStyle + makeNameStyle, } from "../support/Strings"; import { defined, assertNever, panic, numberEnumValues } from "../support/Support"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { EnumOption, StringOption, Option, getOptionValues, OptionValues } from "../RendererOptions"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; import { assert } from "../support/Support"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; import { getAccessorName } from "../attributes/AccessorNames"; import { enumCaseValues } from "../attributes/EnumValues"; @@ -58,10 +63,10 @@ export const cJSONOptions = { "Source code generation type, whether to generate single or multiple source files", [ ["single-source", true], - ["multi-source", false] + ["multi-source", false], ], "single-source", - "secondary" + "secondary", ), typeIntegerSize: new EnumOption( "integer-size", @@ -70,36 +75,36 @@ export const cJSONOptions = { ["int8_t", "int8_t"], ["int16_t", "int16_t"], ["int32_t", "int32_t"], - ["int64_t", "int64_t"] + ["int64_t", "int64_t"], ], "int64_t", - "secondary" + "secondary", ), hashtableSize: new StringOption( "hashtable-size", "Hashtable size, used when maps are created (64 by default)", "SIZE", - "64" + "64", ), addTypedefAlias: new EnumOption( "typedef-alias", "Add typedef alias to unions, structs, and enums (no typedef by default)", [ ["no-typedef", false], - ["add-typedef", true] + ["add-typedef", true], ], "no-typedef", - "secondary" + "secondary", ), printStyle: new EnumOption( "print-style", "Which cJSON print should be used (formatted by default)", [ ["print-formatted", false], - ["print-unformatted", true] + ["print-unformatted", true], ], "print-formatted", - "secondary" + "secondary", ), typeNamingStyle: new EnumOption("type-style", "Naming style for types", [ pascalValue, @@ -107,7 +112,7 @@ export const cJSONOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue + camelUpperAcronymsValue, ]), memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ underscoreValue, @@ -115,7 +120,7 @@ export const cJSONOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue + camelUpperAcronymsValue, ]), enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ upperUnderscoreValue, @@ -123,8 +128,8 @@ export const cJSONOptions = { pascalValue, camelValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue - ]) + camelUpperAcronymsValue, + ]), }; /* cJSON generator target language */ @@ -135,7 +140,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * @params names: names * @param extension: extension of files */ - constructor(displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { + constructor (displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { super(displayName, names, extension); } @@ -143,7 +148,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Return cJSON generator options * @return cJSON generator options array */ - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ cJSONOptions.typeSourceStyle, cJSONOptions.typeIntegerSize, @@ -152,7 +157,7 @@ export class CJSONTargetLanguage extends TargetLanguage { cJSONOptions.hashtableSize, cJSONOptions.typeNamingStyle, cJSONOptions.memberNamingStyle, - cJSONOptions.enumeratorNamingStyle + cJSONOptions.enumeratorNamingStyle, ]; } @@ -160,7 +165,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Indicate if language support union with both number types * @return true */ - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } @@ -168,7 +173,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Indicate if language support optional class properties * @return true */ - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } @@ -178,7 +183,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * @param untypedOptionValues * @return cJSON renderer */ - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): CJSONRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): CJSONRenderer { return new CJSONRenderer(this, renderContext, getOptionValues(cJSONOptions, untypedOptionValues)); } } @@ -306,7 +311,7 @@ const keywords = [ "String", "StringArray", "StringReference", - "True" + "True", ]; /* Used to build forbidden global names */ @@ -328,46 +333,53 @@ export enum IncludeKind { } /* Used to map includes */ -export type IncludeRecord = { +export interface IncludeRecord { kind: IncludeKind | undefined /* How to include that */; typeKind: TypeKind | undefined /* What exactly to include */; -}; +} /* Used to map includes */ -export type TypeRecord = { +export interface TypeRecord { + forceInclude: boolean; + level: number; name: Name; type: Type; - level: number; variant: boolean; - forceInclude: boolean; -}; +} /* Map each and every unique type to a include kind, e.g. how to include the given type */ export type IncludeMap = Map; /* cJSON type */ -export type TypeCJSON = { +export interface TypeCJSON { + addToObject: Sourcelike /* cJSON add to object function */; cType: Sourcelike /* C type */; - optionalQualifier: string /* C optional qualifier, empty string if not defined */; cjsonType: string /* cJSON type */; - isType: Sourcelike /* cJSON check type function */; - getValue: Sourcelike /* cJSON get value function */; - addToObject: Sourcelike /* cJSON add to object function */; createObject: Sourcelike /* cJSON create object function */; deleteType: Sourcelike /* cJSON delete function */; - items: TypeCJSON | undefined /* Sub-items, used for arrays and map */; + getValue: Sourcelike /* cJSON get value function */; isNullable: boolean /* True if the field is nullable */; -}; + isType: Sourcelike /* cJSON check type function */; + items: TypeCJSON | undefined /* Sub-items, used for arrays and map */; + optionalQualifier: string /* C optional qualifier, empty string if not defined */; +} /* cJSON renderer */ export class CJSONRenderer extends ConvenienceRenderer { private currentFilename: string | undefined; /* Current filename */ - private memberNameStyle: NameStyle; /* Member name style */ - private namedTypeNameStyle: NameStyle; /* Named type name style */ - private forbiddenGlobalNames: string[]; /* Forbidden global names */ + + private readonly memberNameStyle: NameStyle; /* Member name style */ + + private readonly namedTypeNameStyle: NameStyle; /* Named type name style */ + + private readonly forbiddenGlobalNames: string[]; /* Forbidden global names */ + protected readonly typeIntegerSize: string; /* Integer code generation type */ + protected readonly hashtableSize: string; /* Hashtable default size */ + protected readonly typeNamingStyle: NamingStyle; /* Type naming style */ + protected readonly enumeratorNamingStyle: NamingStyle; /* Enum naming style */ /** @@ -376,10 +388,10 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param renderContext: render context * @param _options: renderer options */ - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); this.typeIntegerSize = _options.typeIntegerSize; @@ -399,7 +411,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for namespace * @return Forbidden names for namespace */ - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return [...keywords, ...this.forbiddenGlobalNames]; } @@ -407,7 +419,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for enums * @return Forbidden names for enums */ - protected forbiddenForEnumCases(_enumType: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_enumType: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -415,7 +427,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for unions members * @return Forbidden names for unions members */ - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -423,7 +435,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for objects * @return Forbidden names for objects */ - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -431,7 +443,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build types member names * @return types member namer */ - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("types", this.namedTypeNameStyle); } @@ -439,7 +451,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build object properties member names * @return object properties member namer */ - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return funPrefixNamer("members", this.memberNameStyle); } @@ -447,7 +459,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build union member names * @return union member namer */ - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return funPrefixNamer("members", this.memberNameStyle); } @@ -455,7 +467,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build enum member names * @return enum member namer */ - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("enumerators", makeNameStyle(this.enumeratorNamingStyle, legalizeName)); } @@ -467,11 +479,11 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param lookup: Lookup function * @return Proposed union member name */ - protected proposeUnionMemberName( + protected proposeUnionMemberName ( unionType: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { let fieldName = super.proposeUnionMemberName(unionType, unionName, fieldType, lookup); if ("bool" === fieldName) { @@ -479,6 +491,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else if ("double" === fieldName) { fieldName = "number"; } + return fieldName; } @@ -487,7 +500,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param fieldType: the variable type * @param fieldName: name of the variable */ - protected emitTypdefAlias(fieldType: Type, fieldName: Name) { + protected emitTypdefAlias (fieldType: Type, fieldName: Name) { if (this._options.addTypedefAlias) { this.emitLine("typedef ", this.quicktypeTypeToCJSON(fieldType, false).cType, " ", fieldName, ";"); this.ensureBlankLine(); @@ -498,7 +511,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create header file(s) * @param proposedFilename: source filename provided from stdin */ - protected emitSourceStructure(proposedFilename: string): void { + protected emitSourceStructure (proposedFilename: string): void { /* Depending of source style option, generate a unique header or multiple header files */ if (this._options.typeSourceStyle) { this.emitSingleSourceStructure(proposedFilename); @@ -511,7 +524,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create a single header file with types and generators * @param proposedFilename: source filename provided from stdin */ - protected emitSingleSourceStructure(proposedFilename: string): void { + protected emitSingleSourceStructure (proposedFilename: string): void { /* Create file */ this.startFile(proposedFilename); @@ -539,12 +552,12 @@ export class CJSONRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevelTypedef(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined + type => this.namedTypeToNameForTopLevel(type) === undefined, ); /* Create enum prototypes */ this.forEachEnum("leading-and-interposing", (enumType: EnumType, _enumName: Name) => - this.emitEnumPrototypes(enumType) + this.emitEnumPrototypes(enumType), ); /* Create union prototypes */ @@ -552,19 +565,19 @@ export class CJSONRenderer extends ConvenienceRenderer { /* Create class prototypes */ this.forEachObject("leading-and-interposing", (classType: ClassType, _className: Name) => - this.emitClassPrototypes(classType) + this.emitClassPrototypes(classType), ); /* Create top level prototypes */ this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevelPrototypes(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined + type => this.namedTypeToNameForTopLevel(type) === undefined, ); /* Create enum functions */ this.forEachEnum("leading-and-interposing", (enumType: EnumType, _enumName: Name) => - this.emitEnumFunctions(enumType) + this.emitEnumFunctions(enumType), ); /* Create union functions */ @@ -572,14 +585,14 @@ export class CJSONRenderer extends ConvenienceRenderer { /* Create class functions */ this.forEachObject("leading-and-interposing", (classType: ClassType, _className: Name) => - this.emitClassFunctions(classType) + this.emitClassFunctions(classType), ); /* Create top level functions */ this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevelFunctions(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined + type => this.namedTypeToNameForTopLevel(type) === undefined, ); /* Close file */ @@ -589,7 +602,7 @@ export class CJSONRenderer extends ConvenienceRenderer { /** * Function called to create a multiple header files with types and generators */ - protected emitMultiSourceStructure(): void { + protected emitMultiSourceStructure (): void { /* Array of includes */ let includes: string[]; @@ -604,14 +617,14 @@ export class CJSONRenderer extends ConvenienceRenderer { }, (unionType, _name) => { this.emitUnion(unionType, includes); - } + }, ); /* Create top level file */ this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevel(type, className, includes), - type => this.namedTypeToNameForTopLevel(type) === undefined + type => this.namedTypeToNameForTopLevel(type) === undefined, ); } @@ -620,7 +633,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param enumType: enum type * @param includes: Array of includes */ - protected emitEnum(enumType: EnumType, includes: string[]): void { + protected emitEnum (enumType: EnumType, includes: string[]): void { /* Create file */ const enumName = this.nameForNamedType(enumType); const filename = this.sourcelikeToString(enumName).concat(".h"); @@ -647,7 +660,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create enum typedef * @param enumType: enum type */ - protected emitEnumTypedef(enumType: EnumType): void { + protected emitEnumTypedef (enumType: EnumType): void { /* FIXME: Now there is a language with need of global enum name, see FIXME in makeNameForEnumCase of ConvenienceRenderer.ts, should simplify here when fixed */ const enumName = this.nameForNamedType(enumType); @@ -672,7 +685,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypdefAlias(enumType, enumName); @@ -682,7 +695,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create enum prototypes * @param enumType: enum type */ - protected emitEnumPrototypes(enumType: EnumType): void { + protected emitEnumPrototypes (enumType: EnumType): void { const enumName = this.nameForNamedType(enumType); this.emitLine("enum ", enumName, " cJSON_Get", enumName, "Value(", this.withConst("cJSON"), " * j);"); @@ -694,7 +707,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create enum functions * @param enumType: enum type */ - protected emitEnumFunctions(enumType: EnumType): void { + protected emitEnumFunctions (enumType: EnumType): void { const enumName = this.nameForNamedType(enumType); /* Create cJSON to enumName generator function */ @@ -706,13 +719,13 @@ export class CJSONRenderer extends ConvenienceRenderer { this.forEachEnumCase(enumType, "none", (name, jsonName) => { this.emitLine( onFirst ? "" : "else ", - 'if (!strcmp(cJSON_GetStringValue(j), "', + "if (!strcmp(cJSON_GetStringValue(j), \"", jsonName, - '")) x = ', + "\")) x = ", combinedName, "_", name, - ";" + ";", ); onFirst = false; }); @@ -732,9 +745,9 @@ export class CJSONRenderer extends ConvenienceRenderer { combinedName, "_", name, - ': j = cJSON_CreateString("', + ": j = cJSON_CreateString(\"", jsonName, - '"); break;' + "\"); break;", ); }); }); @@ -748,7 +761,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param unionType: union type * @param includes: Array of includes */ - protected emitUnion(unionType: UnionType, includes: string[]): void { + protected emitUnion (unionType: UnionType, includes: string[]): void { /* Create file */ const unionName = this.nameForNamedType(unionType); const filename = this.sourcelikeToString(unionName).concat(".h"); @@ -775,7 +788,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create union typedef * @param unionType: union type */ - protected emitUnionTypedef(unionType: UnionType): void { + protected emitUnionTypedef (unionType: UnionType): void { const [_hasNull, nonNulls] = removeNullFromUnion(unionType); const unionName = this.nameForNamedType(unionType); @@ -795,16 +808,16 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.optionalQualifier, " ", this.nameForUnionMember(unionType, type), - ";" + ";", ); } }, "value", - true + true, ); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypdefAlias(unionType, unionName); @@ -814,7 +827,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create union prototypes * @param unionType: union type */ - protected emitUnionPrototypes(unionType: UnionType): void { + protected emitUnionPrototypes (unionType: UnionType): void { const unionName = this.nameForNamedType(unionType); this.emitLine("struct ", unionName, " * cJSON_Get", unionName, "Value(const cJSON * j);"); @@ -827,7 +840,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create union functions * @param unionType: union type */ - protected emitUnionFunctions(unionType: UnionType): void { + protected emitUnionFunctions (unionType: UnionType): void { const [hasNull, nonNulls] = removeNullFromUnion(unionType); const unionName = this.nameForNamedType(unionType); @@ -843,6 +856,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); onFirst = false; } + for (const type of nonNulls) { const cJSON = this.quicktypeTypeToCJSON(type, false); this.emitBlock([onFirst === true ? "if (" : "else if (", cJSON.isType, "(j))"], () => { @@ -859,7 +873,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", level > 0 ? level.toString() : "", - ")" + ")", ], () => { const add = (cJSON: TypeCJSON, level: number, child_level: number) => { @@ -878,7 +892,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -890,7 +904,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -905,7 +919,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { this.emitLine( @@ -914,7 +928,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));" + "));", ); this.emitBlock( ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], @@ -926,7 +940,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");" + ");", ); this.emitLine( "list_add_tail(x", @@ -935,37 +949,38 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));" + " *));", ); - } + }, ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( ["if (!cJSON_IsNull(e", child_level.toString(), "))"], () => { add(cJSON, level, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( "list_add_tail(x", child_level.toString(), - ", (void *)0xDEADBEEF, sizeof(void *));" + ", (void *)0xDEADBEEF, sizeof(void *));", ); }); } else { add(cJSON, level, child_level); } - } + }, ); this.emitLine( "x->value.", this.nameForUnionMember(unionType, type), " = x", child_level.toString(), - ";" + ";", ); }); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { @@ -977,7 +992,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = hashtable_create(", this.hashtableSize, - ", false);" + ", false);", ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); @@ -987,7 +1002,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", level > 0 ? level.toString() : "", - ")" + ")", ], () => { const add = (cJSON: TypeCJSON, level: number, child_level: number) => { @@ -1008,7 +1023,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -1022,7 +1037,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -1039,7 +1054,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { this.emitLine( @@ -1048,7 +1063,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));" + "));", ); this.emitBlock( ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], @@ -1060,7 +1075,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");" + ");", ); this.emitLine( "hashtable_add(x", @@ -1071,18 +1086,19 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));" + " *));", ); - } + }, ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( ["if (!cJSON_IsNull(e", child_level.toString(), "))"], () => { add(cJSON, level, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( @@ -1090,20 +1106,20 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", e", child_level.toString(), - "->string, (void *)0xDEADBEEF, sizeof(void *));" + "->string, (void *)0xDEADBEEF, sizeof(void *));", ); }); } else { add(cJSON, level, child_level); } - } + }, ); this.emitLine( "x->value.", this.nameForUnionMember(unionType, type), " = x", child_level.toString(), - ";" + ";", ); }); } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { @@ -1112,7 +1128,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), " = (", cJSON.cType, - " *)0xDEADBEEF;" + " *)0xDEADBEEF;", ); } else if (cJSON.cjsonType === "cJSON_String") { this.emitLine( @@ -1120,7 +1136,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), " = strdup(", cJSON.getValue, - "(j));" + "(j));", ); } else { this.emitLine( @@ -1128,7 +1144,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), " = ", cJSON.getValue, - "(j);" + "(j);", ); } }); @@ -1152,6 +1168,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); onFirst = false; } + for (const type of nonNulls) { const cJSON = this.quicktypeTypeToCJSON(type, false); this.emitBlock( @@ -1165,7 +1182,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = ", cJSON.createObject, - "();" + "();", ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( @@ -1176,7 +1193,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { const add = (cJSON: TypeCJSON, child_level: number) => { @@ -1192,7 +1209,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", ", cJSON.items!.createObject, - "());" + "());", ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -1206,7 +1223,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));" + "));", ); } else { this.emitLine( @@ -1216,27 +1233,29 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));" + "));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], () => { add(cJSON, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), - ", cJSON_CreateNull());" + ", cJSON_CreateNull());", ); }); } else { add(cJSON, child_level); } + this.emitLine( "x", child_level.toString(), @@ -1244,7 +1263,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); }); this.emitLine("j = j", child_level.toString(), ";"); @@ -1257,7 +1276,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = ", cJSON.createObject, - "();" + "();", ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine("char **keys", child_level.toString(), " = NULL;"); @@ -1270,7 +1289,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), ", &keys", child_level.toString(), - ");" + ");", ); this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { this.emitBlock( @@ -1283,7 +1302,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)" + "++)", ], () => { this.emitLine( @@ -1298,7 +1317,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);" + "]);", ); const add = (cJSON: TypeCJSON, child_level: number) => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -1318,7 +1337,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "], ", cJSON.items!.createObject, - "());" + "());", ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -1337,7 +1356,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));" + "));", ); } else { this.emitLine( @@ -1352,20 +1371,21 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));" + "));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")" + ")", ], () => { add(cJSON, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( @@ -1376,13 +1396,13 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "], cJSON_CreateNull());" + "], cJSON_CreateNull());", ); }); } else { add(cJSON, child_level); } - } + }, ); this.emitLine("cJSON_free(keys", child_level.toString(), ");"); }); @@ -1398,16 +1418,16 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.createObject, "(x->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); } - } + }, ); onFirst = false; } }); this.emitLine("return j;"); - } + }, ); this.ensureBlankLine(); @@ -1427,7 +1447,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ")" + ")", ], () => { this.emitLine( @@ -1438,7 +1458,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -1459,19 +1479,20 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); - } + }, ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); } } + this.emitLine( "x", child_level.toString(), @@ -1479,7 +1500,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); }); this.emitLine( @@ -1488,9 +1509,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); - } + }, ); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { const level = 0; @@ -1501,7 +1522,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ")" + ")", ], () => { this.emitLine("char **keys", child_level.toString(), " = NULL;"); @@ -1514,7 +1535,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), ", &keys", child_level.toString(), - ");" + ");", ); this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { this.emitBlock( @@ -1527,7 +1548,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)" + "++)", ], () => { this.emitLine( @@ -1542,7 +1563,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);" + "]);", ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -1560,28 +1581,28 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")" + ")", ], () => { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); - } + }, ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); } } }); - } + }, ); this.emitLine("cJSON_free(keys", child_level.toString(), ");"); }); @@ -1591,9 +1612,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); - } + }, ); } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { /* Nothing to do */ @@ -1606,7 +1627,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.deleteType, "(x->value.", this.nameForUnionMember(unionType, type), - ");" + ");", ); } else { /* Nothing to do */ @@ -1614,6 +1635,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); onFirst = false; } + this.emitLine("cJSON_free(x);"); }); }); @@ -1625,7 +1647,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param classType: class type * @param includes: Array of includes */ - protected emitClass(classType: ClassType, includes: string[]): void { + protected emitClass (classType: ClassType, includes: string[]): void { /* Create file */ const className = this.nameForNamedType(classType); const filename = this.sourcelikeToString(className).concat(".h"); @@ -1652,7 +1674,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create class typedef * @param classType: class type */ - protected emitClassTypedef(classType: ClassType): void { + protected emitClassTypedef (classType: ClassType): void { const className = this.nameForNamedType(classType); this.emitDescription(this.descriptionForType(classType)); @@ -1668,12 +1690,12 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.optionalQualifier, " ", name, - ";" + ";", ); }); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypdefAlias(classType, className); @@ -1683,7 +1705,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create class prototypes * @param classType: class type */ - protected emitClassPrototypes(classType: ClassType): void { + protected emitClassPrototypes (classType: ClassType): void { const className = this.nameForNamedType(classType); this.emitLine("struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s);"); @@ -1698,7 +1720,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create class functions * @param classType: class type */ - protected emitClassFunctions(classType: ClassType): void { + protected emitClassFunctions (classType: ClassType): void { const className = this.nameForNamedType(classType); /* Create string to className generator function */ @@ -1714,7 +1736,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); @@ -1746,7 +1768,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level2.toString(), ", sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if (cJSON.cjsonType === "cJSON_Map") { /* Not supported */ @@ -1761,7 +1783,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.cType, " *)0xDEADBEEF, sizeof(", cJSON.cType, - " *));" + " *));", ); } else if (cJSON.cjsonType === "cJSON_String") { this.emitLine( @@ -1773,7 +1795,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.cType, - " *));" + " *));", ); } else if ( cJSON.cjsonType === "cJSON_Object" || @@ -1788,7 +1810,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.cType, - " *));" + " *));", ); } else { this.emitLine( @@ -1797,7 +1819,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.cType, - "));" + "));", ); this.emitBlock( ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], @@ -1809,7 +1831,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(e", child_level.toString(), - ");" + ");", ); this.emitLine( "list_add_tail(x", @@ -1818,12 +1840,12 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.cType, - " *));" + " *));", ); - } + }, ); } - } + }, ); }); } else if (type instanceof ClassType) { @@ -1832,23 +1854,23 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock( !cJSON.isNullable ? [ - "if (cJSON_HasObjectItem(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '"))' - ] + "if (cJSON_HasObjectItem(j", + level > 0 ? level.toString() : "", + ", \"", + jsonName, + "\"))", + ] : [ - "if ((cJSON_HasObjectItem(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '")) && (!cJSON_IsNull(cJSON_GetObjectItemCaseSensitive(j', - level > 0 ? level.toString() : "", - ', "', - jsonName, - '"))))' - ], + "if ((cJSON_HasObjectItem(j", + level > 0 ? level.toString() : "", + ", \"", + jsonName, + "\")) && (!cJSON_IsNull(cJSON_GetObjectItemCaseSensitive(j", + level > 0 ? level.toString() : "", + ", \"", + jsonName, + "\"))))", + ], () => { if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { const child_level = level + 1; @@ -1856,7 +1878,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.cType, " * x", child_level.toString(), - " = list_create(false, NULL);" + " = list_create(false, NULL);", ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); @@ -1865,9 +1887,9 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '");' + "\");", ); this.emitBlock( [ @@ -1875,14 +1897,14 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level.toString(), - ")" + ")", ], () => { const add = ( type: Type, cJSON: TypeCJSON, level: number, - child_level: number + child_level: number, ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof ArrayType) { @@ -1895,7 +1917,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level2.toString(), ", sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { panic("Invalid type"); @@ -1913,7 +1935,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -1925,7 +1947,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -1940,7 +1962,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { this.emitLine( @@ -1949,13 +1971,13 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));" + "));", ); this.emitBlock( [ "if (NULL != tmp", level > 0 ? level.toString() : "", - ")" + ")", ], () => { this.emitLine( @@ -1965,7 +1987,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");" + ");", ); this.emitLine( "list_add_tail(x", @@ -1974,34 +1996,35 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));" + " *));", ); - } + }, ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( [ "if (!cJSON_IsNull(e", child_level.toString(), - "))" + "))", ], () => { add(property.type, cJSON, level, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( "list_add_tail(x", child_level.toString(), - ", (void *)0xDEADBEEF, sizeof(void *));" + ", (void *)0xDEADBEEF, sizeof(void *));", ); }); } else { add(property.type, cJSON, level, child_level); } - } + }, ); this.emitLine( "x", @@ -2010,7 +2033,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = x", child_level.toString(), - ";" + ";", ); }); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { @@ -2021,7 +2044,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = hashtable_create(", this.hashtableSize, - ", false);" + ", false);", ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); @@ -2030,9 +2053,9 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '");' + "\");", ); this.emitBlock( [ @@ -2040,14 +2063,14 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level.toString(), - ")" + ")", ], () => { const add = ( type: Type, cJSON: TypeCJSON, level: number, - child_level: number + child_level: number, ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof MapType) { @@ -2062,7 +2085,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level2.toString(), ", sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { panic("Invalid type"); @@ -2082,7 +2105,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -2096,7 +2119,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -2113,7 +2136,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { this.emitLine( @@ -2122,13 +2145,13 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));" + "));", ); this.emitBlock( [ "if (NULL != tmp", level > 0 ? level.toString() : "", - ")" + ")", ], () => { this.emitLine( @@ -2138,7 +2161,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");" + ");", ); this.emitLine( "hashtable_add(x", @@ -2149,22 +2172,23 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));" + " *));", ); - } + }, ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( [ "if (!cJSON_IsNull(e", child_level.toString(), - "))" + "))", ], () => { add(property.type, cJSON, level, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( @@ -2172,13 +2196,13 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", e", child_level.toString(), - "->string, (void *)0xDEADBEEF, sizeof(void *));" + "->string, (void *)0xDEADBEEF, sizeof(void *));", ); }); } else { add(property.type, cJSON, level, child_level); } - } + }, ); this.emitLine( "x", @@ -2187,7 +2211,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = x", child_level.toString(), - ";" + ";", ); }); } else if ( @@ -2201,7 +2225,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = (", cJSON.cType, - " *)0xDEADBEEF;" + " *)0xDEADBEEF;", ); } else if (cJSON.cjsonType === "cJSON_String") { this.emitLine( @@ -2213,9 +2237,9 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '")));' + "\")));", ); } else if ( cJSON.cjsonType === "cJSON_Object" || @@ -2230,9 +2254,9 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '"));' + "\"));", ); } else { if (property.isOptional || cJSON.isNullable) { @@ -2244,7 +2268,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = cJSON_malloc(sizeof(", cJSON.cType, - "))))" + "))))", ], () => { this.emitLine( @@ -2256,11 +2280,11 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '"));' + "\"));", ); - } + }, ); } else { this.emitLine( @@ -2272,13 +2296,13 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '"));' + "\"));", ); } } - } + }, ); if (!property.isOptional && !cJSON.isNullable) { if (cJSON.cjsonType === "cJSON_Array") { @@ -2288,7 +2312,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - " = list_create(false, NULL);" + " = list_create(false, NULL);", ); }); } else if (cJSON.cjsonType === "cJSON_Map") { @@ -2300,7 +2324,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = hashtable_create(", this.hashtableSize, - ", false);" + ", false);", ); }); } else if ( @@ -2315,7 +2339,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = (", cJSON.cType, - " *)0xDEADBEEF;" + " *)0xDEADBEEF;", ); }); } else if (cJSON.cjsonType === "cJSON_String") { @@ -2328,7 +2352,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = cJSON_malloc(sizeof(", cJSON.cType, - "))))" + "))))", ], () => { this.emitLine( @@ -2336,9 +2360,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - "[0] = '\\0';" + "[0] = '\\0';", ); - } + }, ); }); } else { @@ -2348,11 +2372,12 @@ export class CJSONRenderer extends ConvenienceRenderer { }); } }; + recur(classType, 0); }); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); @@ -2375,7 +2400,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = list_get_head(x", level.toString(), - ");" + ");", ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.cjsonType === "cJSON_Array") { @@ -2386,7 +2411,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level2.toString(), - ");" + ");", ); } else if (cJSON.cjsonType === "cJSON_Map") { /* Not supported */ @@ -2398,7 +2423,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", ", cJSON.createObject, - "());" + "());", ); } else if ( cJSON.cjsonType === "cJSON_String" || @@ -2412,7 +2437,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.createObject, "(x", child_level.toString(), - "));" + "));", ); } else { this.emitLine( @@ -2422,15 +2447,16 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.createObject, "(*x", child_level.toString(), - "));" + "));", ); } + this.emitLine( "x", child_level.toString(), " = list_get_next(x", level.toString(), - ");" + ");", ); }); }); @@ -2447,9 +2473,9 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = cJSON_AddArrayToObject(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '");' + "\");", ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( @@ -2460,7 +2486,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); this.emitBlock( ["while (NULL != x", child_level.toString(), ")"], @@ -2468,7 +2494,7 @@ export class CJSONRenderer extends ConvenienceRenderer { const add = ( type: Type, cJSON: TypeCJSON, - child_level: number + child_level: number, ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof ArrayType) { @@ -2479,7 +2505,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level2.toString(), - ");" + ");", ); } else { panic("Invalid type"); @@ -2494,7 +2520,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", ", cJSON.items!.createObject, - "());" + "());", ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -2508,7 +2534,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));" + "));", ); } else { this.emitLine( @@ -2518,31 +2544,33 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));" + "));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")" + ")", ], () => { add(property.type, cJSON, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), - ", cJSON_CreateNull());" + ", cJSON_CreateNull());", ); }); } else { add(property.type, cJSON, child_level); } + this.emitLine( "x", child_level.toString(), @@ -2550,12 +2578,12 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); - } + }, ); }); - } + }, ); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { const child_level = level + 1; @@ -2567,7 +2595,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = ", cJSON.createObject, - "();" + "();", ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine("char **keys", child_level.toString(), " = NULL;"); @@ -2580,7 +2608,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, ", &keys", child_level.toString(), - ");" + ");", ); this.emitBlock( ["if (NULL != keys", child_level.toString(), ")"], @@ -2595,7 +2623,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)" + "++)", ], () => { this.emitLine( @@ -2610,12 +2638,12 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);" + "]);", ); const add = ( type: Type, cJSON: TypeCJSON, - child_level: number + child_level: number, ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof MapType) { @@ -2631,7 +2659,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "], j", child_level2.toString(), - ");" + ");", ); } else { panic("Invalid type"); @@ -2657,7 +2685,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "], ", cJSON.items!.createObject, - "());" + "());", ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -2676,7 +2704,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));" + "));", ); } else { this.emitLine( @@ -2691,20 +2719,21 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));" + "));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")" + ")", ], () => { add(property.type, cJSON, child_level); - } + }, ); this.emitBlock(["else"], () => { this.emitLine( @@ -2715,33 +2744,33 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "], cJSON_CreateNull());" + "], cJSON_CreateNull());", ); }); } else { add(property.type, cJSON, child_level); } - } + }, ); this.emitLine( "cJSON_free(keys", child_level.toString(), - ");" + ");", ); - } + }, ); this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", j', + "\", j", child_level.toString(), - ");" + ");", ); }); - } + }, ); } else if (cJSON.cjsonType === "cJSON_Invalid") { /* Nothing to do */ @@ -2754,20 +2783,20 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '");' + "\");", ); - } + }, ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '");' + "\");", ); } } else if (cJSON.cjsonType === "cJSON_String") { @@ -2778,15 +2807,15 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", x', + "\", x", level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); - } + }, ); if (!property.isOptional && !cJSON.isNullable) { this.emitBlock(["else"], () => { @@ -2794,9 +2823,9 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", "");' + "\", \"\");", ); }); } @@ -2812,32 +2841,32 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", ', + "\", ", cJSON.createObject, "(x", level > 0 ? level.toString() : "", "->", name, - "));" + "));", ); - } + }, ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", ', + "\", ", cJSON.createObject, "(x", level > 0 ? level.toString() : "", "->", name, - "));" + "));", ); } } else if (cJSON.cjsonType === "cJSON_Enum") { @@ -2849,32 +2878,32 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", ', + "\", ", cJSON.createObject, "(*x", level > 0 ? level.toString() : "", "->", name, - "));" + "));", ); - } + }, ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", ', + "\", ", cJSON.createObject, "(x", level > 0 ? level.toString() : "", "->", name, - "));" + "));", ); } } else { @@ -2886,50 +2915,52 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", *x', + "\", *x", level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); - } + }, ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '", x', + "\", x", level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); } } + if (cJSON.isNullable) { this.emitBlock(["else"], () => { this.emitLine( "cJSON_AddNullToObject(j", level > 0 ? level.toString() : "", - ', "', + ", \"", jsonName, - '");' + "\");", ); }); } }); } }; + recur(classType, 0); }); }); this.emitLine("return j;"); - } + }, ); this.ensureBlankLine(); @@ -2960,7 +2991,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = list_get_head(x", level.toString(), - ");" + ");", ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.cjsonType === "cJSON_Array") { @@ -2973,6 +3004,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { this.emitLine(cJSON.deleteType, "(x", child_level.toString(), ");"); } + this.emitLine("x", child_level.toString(), " = list_get_next(x", level.toString(), ");"); }); } else if (type instanceof ClassType) { @@ -2991,7 +3023,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -3001,7 +3033,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); } else { panic("Invalid type"); @@ -3022,19 +3054,20 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); - } + }, ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); } } + this.emitLine( "x", child_level.toString(), @@ -3042,7 +3075,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); }); this.emitLine( @@ -3051,9 +3084,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); - } + }, ); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { const child_level = level + 1; @@ -3070,7 +3103,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, ", &keys", child_level.toString(), - ");" + ");", ); this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { this.emitBlock( @@ -3083,7 +3116,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)" + "++)", ], () => { this.emitLine( @@ -3098,7 +3131,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);" + "]);", ); this.emitBlock( ["if (NULL != x", child_level.toString(), ")"], @@ -3110,7 +3143,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); } else { panic("Invalid type"); @@ -3128,29 +3161,29 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")" + ")", ], () => { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); - } + }, ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");" + ");", ); } } - } + }, ); - } + }, ); this.emitLine("cJSON_free(keys", child_level.toString(), ");"); }); @@ -3160,9 +3193,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); - } + }, ); } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { /* Nothing to do */ @@ -3180,9 +3213,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); - } + }, ); } else { if (property.isOptional || cJSON.isNullable) { @@ -3195,15 +3228,16 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");" + ");", ); - } + }, ); } } }); } }; + recur(classType, 0); this.emitLine("cJSON_free(x);"); }); @@ -3217,7 +3251,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param className: top level class name * @param includes: Array of includes */ - protected emitTopLevel(type: Type, className: Name, includes: string[]): void { + protected emitTopLevel (type: Type, className: Name, includes: string[]): void { /* Create file */ const filename = this.sourcelikeToString(className).concat(".h"); this.startFile(filename); @@ -3246,7 +3280,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type of the top level element * @param className: top level class name */ - protected emitTopLevelTypedef(type: Type, className: Name): void { + protected emitTopLevelTypedef (type: Type, className: Name): void { this.emitBlock( ["struct ", className], () => { @@ -3255,11 +3289,11 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.cType, cJSON.optionalQualifier !== "" ? " " : "", cJSON.optionalQualifier, - " value;" + " value;", ); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypdefAlias(type, className); @@ -3270,7 +3304,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type of the top level element * @param className: top level class name */ - protected emitTopLevelPrototypes(_type: Type, className: Name): void { + protected emitTopLevelPrototypes (_type: Type, className: Name): void { this.emitLine("struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s);"); this.emitLine("struct ", className, " * cJSON_Get", className, "Value(", this.withConst("cJSON"), " * j);"); this.emitLine("cJSON * cJSON_Create", className, "(", this.withConst(["struct ", className]), " * x);"); @@ -3284,7 +3318,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type of the top level element * @param className: top level class name */ - protected emitTopLevelFunctions(type: Type, className: Name): void { + protected emitTopLevelFunctions (type: Type, className: Name): void { /* Create string to className generator function */ this.emitBlock( ["struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s)"], @@ -3298,7 +3332,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); @@ -3330,7 +3364,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEAF, sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -3338,7 +3372,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e)), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { this.emitLine( @@ -3346,17 +3380,18 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock(["if (!cJSON_IsNull(e))"], () => { add(cJSON); }); this.emitBlock(["else"], () => { this.emitLine( - "list_add_tail(x->value, (void *)0xDEADBEEF, sizeof(void *));" + "list_add_tail(x->value, (void *)0xDEADBEEF, sizeof(void *));", ); }); } else { @@ -3383,7 +3418,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -3391,7 +3426,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e)), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } else { this.emitLine( @@ -3399,17 +3434,18 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e), sizeof(", cJSON.items!.cType, - " *));" + " *));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock(["if (!cJSON_IsNull(e))"], () => { add(cJSON); }); this.emitBlock(["else"], () => { this.emitLine( - "hashtable_add(x->value, e->string, (void *)0xDEADBEEF, sizeof(void *));" + "hashtable_add(x->value, e->string, (void *)0xDEADBEEF, sizeof(void *));", ); }); } else { @@ -3429,7 +3465,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); @@ -3457,7 +3493,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "cJSON_AddItemToArray(j, ", cJSON.items!.createObject, - "());" + "());", ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -3467,16 +3503,17 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "cJSON_AddItemToArray(j, ", cJSON.items!.createObject, - "(x1));" + "(x1));", ); } else { this.emitLine( "cJSON_AddItemToArray(j, ", cJSON.items!.createObject, - "(*x1));" + "(*x1));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock(["if ((void *)0xDEADBEEF != x1)"], () => { add(cJSON); @@ -3487,6 +3524,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { add(cJSON); } + this.emitLine("x1 = list_get_next(x->value);"); }); }); @@ -3501,7 +3539,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["for (size_t index = 0; index < count; index++)"], () => { this.emitLine( cJSON.items!.cType, - " *x2 = hashtable_lookup(x->value, keys[index]);" + " *x2 = hashtable_lookup(x->value, keys[index]);", ); const add = (cJSON: TypeCJSON) => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -3515,7 +3553,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j, keys[index], ", cJSON.items!.createObject, - "());" + "());", ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -3526,17 +3564,18 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j, keys[index], ", cJSON.items!.createObject, - "(x2));" + "(x2));", ); } else { this.emitLine( cJSON.addToObject, "(j, keys[index], ", cJSON.items!.createObject, - "(*x2));" + "(*x2));", ); } }; + if (cJSON.items!.isNullable) { this.emitBlock(["if ((void *)0xDEADBEEF != x2)"], () => { add(cJSON); @@ -3544,7 +3583,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["else"], () => { this.emitLine( cJSON.addToObject, - "(j, keys[index], cJSON_CreateNull());" + "(j, keys[index], cJSON_CreateNull());", ); }); } else { @@ -3564,7 +3603,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }); this.emitLine("return j;"); - } + }, ); this.ensureBlankLine(); @@ -3597,6 +3636,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { this.emitLine(cJSON.items!.deleteType, "(x1);"); } + this.emitLine("x1 = list_get_next(x->value);"); }); this.emitLine(cJSON.deleteType, "(x->value);"); @@ -3633,6 +3673,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { /* Nothing to do */ } + this.emitLine("cJSON_free(x);"); }); }); @@ -3646,7 +3687,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param isNullable: true if the field is nullable * @return cJSON type */ - protected quicktypeTypeToCJSON(t: Type, isOptional: boolean, isNullable = false): TypeCJSON { + protected quicktypeTypeToCJSON (t: Type, isOptional: boolean, isNullable = false): TypeCJSON { /* Compute cJSON type */ return matchType( t, @@ -3661,7 +3702,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "", deleteType: "", items: undefined, - isNullable + isNullable, }; }, _nullType => { @@ -3675,7 +3716,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNull", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, _boolType => { @@ -3689,7 +3730,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateBool", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, _integerType => { @@ -3703,7 +3744,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNumber", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, _doubleType => { @@ -3717,7 +3758,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNumber", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, _stringType => { @@ -3731,7 +3772,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateString", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, arrayType => { @@ -3746,7 +3787,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateArray", deleteType: "list_release", items, - isNullable + isNullable, }; }, classType => { @@ -3760,7 +3801,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: ["cJSON_Create", this.nameForNamedType(classType)], deleteType: ["cJSON_Delete", this.nameForNamedType(classType)], items: undefined, - isNullable + isNullable, }; }, mapType => { @@ -3775,7 +3816,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateObject", deleteType: "hashtable_release", items, - isNullable + isNullable, }; }, enumType => { @@ -3789,7 +3830,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: ["cJSON_Create", this.nameForNamedType(enumType)], deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, unionType => { @@ -3807,10 +3848,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: ["cJSON_Create", this.nameForNamedType(unionType)], deleteType: ["cJSON_Delete", this.nameForNamedType(unionType)], items: undefined, - isNullable + isNullable, }; } - } + }, ); } @@ -3818,7 +3859,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create a file * @param proposedFilename: source filename provided from stdin */ - protected startFile(proposedFilename: Sourcelike): void { + protected startFile (proposedFilename: Sourcelike): void { /* Check if previous file is closed, create a new file */ assert(this.currentFilename === undefined, "Previous file wasn't finished"); if (proposedFilename !== undefined) { @@ -3836,7 +3877,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "To get json data from cJSON object use the following: struct * data = cJSON_GetValue();", "To get cJSON object from json data use the following: cJSON * cjson = cJSON_Create();", "To print json string from json data use the following: char * string = cJSON_Print();", - "To delete json data use the following: cJSON_Delete();" + "To delete json data use the following: cJSON_Delete();", ]); this.ensureBlankLine(); @@ -3844,18 +3885,18 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "#ifndef __", allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__" + "__", ); this.emitLine( "#define __", allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__" + "__", ); this.ensureBlankLine(); /* Write C++ guard */ this.emitLine("#ifdef __cplusplus"); - this.emitLine('extern "C" {'); + this.emitLine("extern \"C\" {"); this.emitLine("#endif"); this.ensureBlankLine(); @@ -3886,7 +3927,7 @@ export class CJSONRenderer extends ConvenienceRenderer { /** * Function called to close current file */ - protected finishFile(): void { + protected finishFile (): void { /* Check if file has been created */ if (this.currentFilename !== undefined) { /* Write C++ guard */ @@ -3899,7 +3940,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "#endif /* __", allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__ */" + "__ */", ); this.ensureBlankLine(); @@ -3914,7 +3955,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @note If returning true, canBeForwardDeclared must be declared * @return Always returns true */ - protected get needsTypeDeclarationBeforeUse(): boolean { + protected get needsTypeDeclarationBeforeUse (): boolean { return true; } @@ -3922,7 +3963,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Check if type can be forward declared * @return true for classes, false otherwise */ - protected canBeForwardDeclared(type: Type): boolean { + protected canBeForwardDeclared (type: Type): boolean { return type.kind === "class"; } @@ -3930,7 +3971,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Add const to wanted Sourcelike * @return Const Sourcelike */ - protected withConst(s: Sourcelike): Sourcelike { + protected withConst (s: Sourcelike): Sourcelike { return ["const ", s]; } @@ -3939,15 +3980,15 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param name: filename to include * @pram global: true if global include, false otherwise (default) */ - protected emitIncludeLine(name: Sourcelike, global = false): void { - this.emitLine("#include ", global ? "<" : '"', name, global ? ">" : '"'); + protected emitIncludeLine (name: Sourcelike, global = false): void { + this.emitLine("#include ", global ? "<" : "\"", name, global ? ">" : "\""); } /** * Emit description block * @param lines: description block lines */ - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } @@ -3959,12 +4000,12 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param withSemicolon: true to add semicolon at the end of the block, false otherwise * @param withIndent: true to indent the block (default), false otherwise */ - protected emitBlock( + protected emitBlock ( line: Sourcelike, f: () => void, withName = "", withSemicolon = false, - withIndent = true + withIndent = true, ): void { this.emitLine(line, " {"); this.preventBlankLine(); @@ -3973,6 +4014,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { f(); } + this.preventBlankLine(); if (withSemicolon) { if (withName !== "") { @@ -3994,7 +4036,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: class, union or enum type * @param filename: current file name */ - protected emitIncludes(type: ClassType | UnionType | EnumType, filename: string): void { + protected emitIncludes (type: ClassType | UnionType | EnumType, filename: string): void { /* List required includes */ const includes: IncludeMap = new Map(); if (type instanceof UnionType) { @@ -4014,6 +4056,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }); } + this.ensureBlankLine(); } @@ -4023,7 +4066,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param includes: include map * @param propertyType: property type */ - protected updateIncludes(isClassMember: boolean, includes: IncludeMap, propertyType: Type): void { + protected updateIncludes (isClassMember: boolean, includes: IncludeMap, propertyType: Type): void { const propTypes = this.generatedTypes(isClassMember, propertyType); for (const t of propTypes) { const typeName = this.sourcelikeToString(t.name); @@ -4054,6 +4097,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } } } + if (includes.has(typeName)) { const incKind = includes.get(typeName); /* If we already include the type as typed include, do not write it over with forward declare */ @@ -4072,7 +4116,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type * @return Type record array */ - protected generatedTypes(isClassMember: boolean, type: Type): TypeRecord[] { + protected generatedTypes (isClassMember: boolean, type: Type): TypeRecord[] { const result: TypeRecord[] = []; const recur = (forceInclude: boolean, isVariant: boolean, l: number, t: Type) => { if (t instanceof ArrayType) { @@ -4083,7 +4127,7 @@ export class CJSONRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude + forceInclude, }); } else if (t instanceof MapType) { recur(forceInclude, isVariant, l + 1, t.values); @@ -4093,7 +4137,7 @@ export class CJSONRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude: false + forceInclude: false, }); } else if (t instanceof UnionType) { /** @@ -4117,7 +4161,7 @@ export class CJSONRenderer extends ConvenienceRenderer { type: t, level: l, variant: true, - forceInclude + forceInclude, }); /** intentional "fall-through", add all subtypes as well - but forced include */ } @@ -4130,6 +4174,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } } }; + recur(false, false, 0, type); return result; } diff --git a/packages/quicktype-core/src/language/CPlusPlus.ts b/packages/quicktype-core/src/language/CPlusPlus.ts index 5adff56d2..c486c7827 100644 --- a/packages/quicktype-core/src/language/CPlusPlus.ts +++ b/packages/quicktype-core/src/language/CPlusPlus.ts @@ -5,32 +5,39 @@ import { iterableFirst, iterableFind, iterableSome, - withDefault + withDefault, } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { Type, TypeKind, ClassType, ClassProperty, ArrayType, MapType, EnumType, UnionType } from "../Type"; +import { type Type, type TypeKind, type ClassProperty} from "../Type"; +import { ClassType, ArrayType, MapType, EnumType, UnionType } from "../Type"; import { nullableFromUnion, matchType, removeNullFromUnion, isNamedType, directlyReachableTypes } from "../TypeUtils"; -import { NameStyle, Name, Namer, funPrefixNamer, DependencyName } from "../Naming"; -import { Sourcelike, maybeAnnotated } from "../Source"; +import { type NameStyle, type Name, type Namer} from "../Naming"; +import { funPrefixNamer, DependencyName } from "../Naming"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; +import { + type NamingStyle} from "../support/Strings"; import { legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit, stringEscape, - NamingStyle, - makeNameStyle + makeNameStyle, } from "../support/Strings"; import { defined, assertNever, panic, numberEnumValues } from "../support/Support"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { StringOption, EnumOption, BooleanOption, Option, getOptionValues, OptionValues } from "../RendererOptions"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { StringOption, EnumOption, BooleanOption, getOptionValues } from "../RendererOptions"; import { assert } from "../support/Support"; -import { Declaration } from "../DeclarationIR"; -import { RenderContext } from "../Renderer"; +import { type Declaration } from "../DeclarationIR"; +import { type RenderContext } from "../Renderer"; import { getAccessorName } from "../attributes/AccessorNames"; import { enumCaseValues } from "../attributes/EnumValues"; -import { minMaxValueForType, minMaxLengthForType, patternForType, MinMaxConstraint } from "../attributes/Constraints"; +import { type MinMaxConstraint } from "../attributes/Constraints"; +import { minMaxValueForType, minMaxLengthForType, patternForType } from "../attributes/Constraints"; const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; const underscoreValue: [string, NamingStyle] = ["underscore-case", "underscore"]; @@ -45,47 +52,47 @@ export const cPlusPlusOptions = { "Source code generation type, whether to generate single or multiple source files", [ ["single-source", true], - ["multi-source", false] + ["multi-source", false], ], "single-source", - "secondary" + "secondary", ), includeLocation: new EnumOption( "include-location", "Whether json.hpp is to be located globally or locally", [ ["local-include", true], - ["global-include", false] + ["global-include", false], ], "local-include", - "secondary" + "secondary", ), codeFormat: new EnumOption( "code-format", "Generate classes with getters/setters, instead of structs", [ ["with-struct", false], - ["with-getter-setter", true] + ["with-getter-setter", true], ], - "with-getter-setter" + "with-getter-setter", ), wstring: new EnumOption( "wstring", "Store strings using Utf-16 std::wstring, rather than Utf-8 std::string", [ ["use-string", false], - ["use-wstring", true] + ["use-wstring", true], ], - "use-string" + "use-string", ), westConst: new EnumOption( "const-style", "Put const to the left/west (const T) or right/east (T const)", [ ["west-const", true], - ["east-const", false] + ["east-const", false], ], - "west-const" + "west-const", ), justTypes: new BooleanOption("just-types", "Plain types only", false), namespace: new StringOption("namespace", "Name of the generated namespace(s)", "NAME", "quicktype"), @@ -96,7 +103,7 @@ export const cPlusPlusOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue + camelUpperAcronymsValue, ]), memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ underscoreValue, @@ -104,7 +111,7 @@ export const cPlusPlusOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue + camelUpperAcronymsValue, ]), enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ upperUnderscoreValue, @@ -112,18 +119,18 @@ export const cPlusPlusOptions = { pascalValue, camelValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue + camelUpperAcronymsValue, ]), boost: new BooleanOption("boost", "Require a dependency on boost. Without boost, C++17 is required", true), - hideNullOptional: new BooleanOption("hide-null-optional", "Hide null value for optional field", false) + hideNullOptional: new BooleanOption("hide-null-optional", "Hide null value for optional field", false), }; export class CPlusPlusTargetLanguage extends TargetLanguage { - constructor(displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { + constructor (displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { super(displayName, names, extension); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ cPlusPlusOptions.justTypes, cPlusPlusOptions.namespace, @@ -137,33 +144,33 @@ export class CPlusPlusTargetLanguage extends TargetLanguage { cPlusPlusOptions.enumeratorNamingStyle, cPlusPlusOptions.enumType, cPlusPlusOptions.boost, - cPlusPlusOptions.hideNullOptional + cPlusPlusOptions.hideNullOptional, ]; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): CPlusPlusRenderer { return new CPlusPlusRenderer(this, renderContext, getOptionValues(cPlusPlusOptions, untypedOptionValues)); } } -function constraintsForType(t: Type): - | { - minMax?: MinMaxConstraint; - minMaxLength?: MinMaxConstraint; - pattern?: string; - } - | undefined { +function constraintsForType (t: Type): +| { + minMax?: MinMaxConstraint, + minMaxLength?: MinMaxConstraint, + pattern?: string, +} +| undefined { const minMax = minMaxValueForType(t); const minMaxLength = minMaxLengthForType(t); const pattern = patternForType(t); @@ -273,7 +280,7 @@ const keywords = [ "final", "transaction_safe", "transaction_safe_dynamic", - "NULL" + "NULL", ]; /// Type to use as an optional if cycle breaking is required @@ -326,26 +333,26 @@ export enum MemberNames { SetPattern } -type ConstraintMember = { - name: MemberNames; +interface ConstraintMember { + cppConstType?: string; + cppType: string; getter: MemberNames; + name: MemberNames; setter: MemberNames; - cppType: string; - cppConstType?: string; -}; +} -export type IncludeRecord = { +export interface IncludeRecord { kind: IncludeKind | undefined /** How to include that */; typeKind: TypeKind | undefined /** What exactly to include */; -}; +} -export type TypeRecord = { +export interface TypeRecord { + forceInclude: boolean; + level: number; name: Name; type: Type; - level: number; variant: boolean; - forceInclude: boolean; -}; +} /** * We map each and every unique type to a include kind, e.g. how @@ -353,57 +360,65 @@ export type TypeRecord = { */ export type IncludeMap = Map; -export type TypeContext = { +export interface TypeContext { + inJsonNamespace: boolean; needsForwardIndirection: boolean; needsOptionalIndirection: boolean; - inJsonNamespace: boolean; -}; +} interface StringType { - getType(): string; - getConstType(): string; - getSMatch(): string; - getRegex(): string; - createStringLiteral(inner: Sourcelike): Sourcelike; - wrapToString(inner: Sourcelike): Sourcelike; - wrapEncodingChange( + createStringLiteral: (inner: Sourcelike) => Sourcelike; + emitHelperFunctions: () => void; + getConstType: () => string; + getRegex: () => string; + getSMatch: () => string; + getType: () => string; + wrapEncodingChange: ( qualifier: Sourcelike[], fromType: Sourcelike, toType: Sourcelike, inner: Sourcelike - ): Sourcelike; - emitHelperFunctions(): void; + ) => Sourcelike; + wrapToString: (inner: Sourcelike) => Sourcelike; } -function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { +function addQualifier (qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { if (qualified.length === 0) { return []; } + return [qualifier, qualified]; } class WrappingCode { - constructor( + constructor ( private readonly start: Sourcelike[], - private readonly end: Sourcelike[] + private readonly end: Sourcelike[], ) {} - wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { + wrap (qualifier: Sourcelike, inner: Sourcelike): Sourcelike { return [addQualifier(qualifier, this.start), inner, this.end]; } } class BaseString { public _stringType: string; + public _constStringType: string; + public _smatch: string; + public _regex: string; + public _stringLiteralPrefix: string; + public _toString: WrappingCode; + public _encodingClass: Sourcelike; + public _encodingFunction: Sourcelike; - constructor( + constructor ( stringType: string, constStringType: string, smatch: string, @@ -411,7 +426,7 @@ class BaseString { stringLiteralPrefix: string, toString: WrappingCode, encodingClass: string, - encodingFunction: string + encodingFunction: string, ) { this._stringType = stringType; this._constStringType = constStringType; @@ -423,27 +438,27 @@ class BaseString { this._encodingFunction = encodingFunction; } - public getType(): string { + public getType (): string { return this._stringType; } - public getConstType(): string { + public getConstType (): string { return this._constStringType; } - public getSMatch(): string { + public getSMatch (): string { return this._smatch; } - public getRegex(): string { + public getRegex (): string { return this._regex; } - public createStringLiteral(inner: Sourcelike): Sourcelike { - return [this._stringLiteralPrefix, '"', inner, '"']; + public createStringLiteral (inner: Sourcelike): Sourcelike { + return [this._stringLiteralPrefix, "\"", inner, "\""]; } - public wrapToString(inner: Sourcelike): Sourcelike { + public wrapToString (inner: Sourcelike): Sourcelike { return this._toString.wrap([], inner); } } @@ -455,31 +470,48 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { private readonly _enumType: string; private readonly _generatedFiles: Set; + private _currentFilename: string | undefined; + private _allTypeNames: Set; + private readonly _gettersAndSettersForPropertyName = new Map(); - private readonly _namespaceNames: ReadonlyArray; + + private readonly _namespaceNames: readonly string[]; + private readonly _memberNameStyle: NameStyle; + private readonly _namedTypeNameStyle: NameStyle; + private readonly _generatedGlobalNames: Map; + private readonly _generatedMemberNames: Map; + private readonly _forbiddenGlobalNames: string[]; + private readonly _memberNamingFunction: Namer; + private readonly _stringType: StringType; + /// The type to use as an optional (std::optional or std::shared) private readonly _optionalType: string; + private readonly _optionalFactory: string; + private readonly _nulloptType: string; + private readonly _variantType: string; + private readonly _variantIndexMethodName: string; protected readonly typeNamingStyle: NamingStyle; + protected readonly enumeratorNamingStyle: NamingStyle; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); @@ -524,14 +556,14 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } // union typeguard - isUnion(t: Type | UnionType): t is UnionType { + isUnion (t: Type | UnionType): t is UnionType { return t.kind === "union"; } // Returns true if the type can be stored in // a stack based optional type. This requires // that the type does not require forward declaration. - isOptionalAsValuePossible(t: Type): boolean { + isOptionalAsValuePossible (t: Type): boolean { if (this.isForwardDeclaredType(t)) return false; if (this.isUnion(t)) { @@ -589,182 +621,184 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { return !this.isCycleBreakerType(tt); } } + return !this.isCycleBreakerType(t); } - isImplicitCycleBreaker(t: Type): boolean { + isImplicitCycleBreaker (t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } // Is likely to return std::optional or boost::optional - optionalTypeStack(): string { + optionalTypeStack (): string { return this._optionalType; } // Is likely to return std::make_optional or boost::optional - optionalFactoryStack(): string { + optionalFactoryStack (): string { return this._optionalFactory; } // Is likely to return std::shared_ptr - optionalTypeHeap(): string { + optionalTypeHeap (): string { return optionalAsSharedType; } // Is likely to return std::make_shared - optionalFactoryHeap(): string { + optionalFactoryHeap (): string { return optionalFactoryAsSharedType; } // Returns the optional type most suitable for the given type. // Classes that don't require forward declarations can be stored // in std::optional ( or boost::optional ) - optionalType(t: Type): string { + optionalType (t: Type): string { if (this.isOptionalAsValuePossible(t)) return this.optionalTypeStack(); else return this.optionalTypeHeap(); } // Returns a label that can be used to distinguish between // heap and stack based optional handling methods - optionalTypeLabel(t: Type): string { + optionalTypeLabel (t: Type): string { if (this.isOptionalAsValuePossible(t)) return "stack"; else return "heap"; } - protected getConstraintMembers(): ConstraintMember[] { + protected getConstraintMembers (): ConstraintMember[] { return [ { name: MemberNames.MinIntValue, getter: MemberNames.GetMinIntValue, setter: MemberNames.SetMinIntValue, - cppType: "int64_t" + cppType: "int64_t", }, { name: MemberNames.MaxIntValue, getter: MemberNames.GetMaxIntValue, setter: MemberNames.SetMaxIntValue, - cppType: "int64_t" + cppType: "int64_t", }, { name: MemberNames.MinDoubleValue, getter: MemberNames.GetMinDoubleValue, setter: MemberNames.SetMinDoubleValue, - cppType: "double" + cppType: "double", }, { name: MemberNames.MaxDoubleValue, getter: MemberNames.GetMaxDoubleValue, setter: MemberNames.SetMaxDoubleValue, - cppType: "double" + cppType: "double", }, { name: MemberNames.MinLength, getter: MemberNames.GetMinLength, setter: MemberNames.SetMinLength, - cppType: "size_t" + cppType: "size_t", }, { name: MemberNames.MaxLength, getter: MemberNames.GetMaxLength, setter: MemberNames.SetMaxLength, - cppType: "size_t" + cppType: "size_t", }, { name: MemberNames.Pattern, getter: MemberNames.GetPattern, setter: MemberNames.SetPattern, cppType: this._stringType.getType(), - cppConstType: this._stringType.getConstType() - } + cppConstType: this._stringType.getConstType(), + }, ]; } - protected lookupGlobalName(type: GlobalNames): string { + protected lookupGlobalName (type: GlobalNames): string { return defined(this._generatedGlobalNames.get(type)); } - protected lookupMemberName(type: MemberNames): string { + protected lookupMemberName (type: MemberNames): string { return defined(this._generatedMemberNames.get(type)); } - protected addGlobalName(type: GlobalNames): void { + protected addGlobalName (type: GlobalNames): void { const genName = this._namedTypeNameStyle(GlobalNames[type]); this._generatedGlobalNames.set(type, genName); this._forbiddenGlobalNames.push(genName); } - protected addMemberName(type: MemberNames): void { + protected addMemberName (type: MemberNames): void { this._generatedMemberNames.set(type, this._memberNameStyle(MemberNames[type])); } - protected setupGlobalNames(): void { + protected setupGlobalNames (): void { for (const v of numberEnumValues(GlobalNames)) { this.addGlobalName(v); } + for (const v of numberEnumValues(MemberNames)) { this.addMemberName(v); } } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return [...keywords, ...this._forbiddenGlobalNames]; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("types", this._namedTypeNameStyle); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return this._memberNamingFunction; } - protected makeUnionMemberNamer(): null { + protected makeUnionMemberNamer (): null { return null; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("enumerators", makeNameStyle(this.enumeratorNamingStyle, legalizeName)); } - protected makeNamesForPropertyGetterAndSetter( + protected makeNamesForPropertyGetterAndSetter ( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name + name: Name, ): [Name, Name, Name] { const getterName = new DependencyName(this._memberNamingFunction, name.order, lookup => `get_${lookup(name)}`); const mutableGetterName = new DependencyName( this._memberNamingFunction, name.order, - lookup => `getMutable_${lookup(name)}` + lookup => `getMutable_${lookup(name)}`, ); const setterName = new DependencyName(this._memberNamingFunction, name.order, lookup => `set_${lookup(name)}`); return [getterName, mutableGetterName, setterName]; } - protected makePropertyDependencyNames( + protected makePropertyDependencyNames ( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return getterAndSetterNames; } - protected withConst(s: Sourcelike): Sourcelike { + protected withConst (s: Sourcelike): Sourcelike { if (this._options.westConst) { return ["const ", s]; } else { @@ -772,11 +806,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitInclude(global: boolean, name: Sourcelike): void { - this.emitLine("#include ", global ? "<" : '"', name, global ? ">" : '"'); + protected emitInclude (global: boolean, name: Sourcelike): void { + this.emitLine("#include ", global ? "<" : "\"", name, global ? ">" : "\""); } - protected startFile(basename: Sourcelike, includeHelper = true): void { + protected startFile (basename: Sourcelike, includeHelper = true): void { assert(this._currentFilename === undefined, "Previous file wasn't finished"); if (basename !== undefined) { this._currentFilename = this.sourcelikeToString(basename); @@ -789,11 +823,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { if (this._options.boost) { this.emitCommentLines([" Boost http://www.boost.org"]); } + this.emitCommentLines([ " json.hpp https://github.com/nlohmann/json", "", " Then include this file, and then do", - "" + "", ]); if (this._options.typeSourceStyle) { @@ -803,6 +838,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } else { this.emitLine("// ", basename, " data = nlohmann::json::parse(jsonString);"); } + if (this._options.wstring) { this.emitLine("//"); this.emitLine("// You can get std::wstring data back out using"); @@ -812,6 +848,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } } + this.ensureBlankLine(); this.emitLine("#pragma once"); @@ -824,6 +861,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitInclude(true, "optional"); } } + if (this.haveNamedUnions) { if (this._options.boost) { this.emitInclude(true, "boost/variant.hpp"); @@ -831,6 +869,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitInclude(true, "variant"); } } + if (!this._options.justTypes) { if (!this._options.includeLocation) { this.emitInclude(true, "nlohmann/json.hpp"); @@ -842,28 +881,29 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitInclude(false, "helper.hpp"); } } + this.ensureBlankLine(); } - protected finishFile(): void { + protected finishFile (): void { super.finishFile(defined(this._currentFilename)); this._currentFilename = undefined; } - protected get needsTypeDeclarationBeforeUse(): boolean { + protected get needsTypeDeclarationBeforeUse (): boolean { return true; } - protected canBeForwardDeclared(t: Type): boolean { + protected canBeForwardDeclared (t: Type): boolean { const kind = t.kind; return kind === "class"; } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock(line: Sourcelike, withSemicolon: boolean, f: () => void, withIndent = true): void { + protected emitBlock (line: Sourcelike, withSemicolon: boolean, f: () => void, withIndent = true): void { this.emitLine(line, " {"); this.preventBlankLine(); if (withIndent) { @@ -871,6 +911,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } else { f(); } + this.preventBlankLine(); if (withSemicolon) { this.emitLine("};"); @@ -879,7 +920,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitNamespaces(namespaceNames: Iterable, f: () => void): void { + protected emitNamespaces (namespaceNames: Iterable, f: () => void): void { const namesArray = toReadonlyArray(namespaceNames); const first = namesArray[0]; if (first === undefined) { @@ -889,43 +930,46 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ["namespace ", first], false, () => this.emitNamespaces(namesArray.slice(1), f), - namesArray.length === 1 + namesArray.length === 1, ); } } - protected cppTypeInOptional( + protected cppTypeInOptional ( nonNulls: ReadonlySet, ctx: TypeContext, withIssues: boolean, - forceNarrowString: boolean + forceNarrowString: boolean, ): Sourcelike { if (nonNulls.size === 1) { return this.cppType(defined(iterableFirst(nonNulls)), ctx, withIssues, forceNarrowString, false); } + const typeList: Sourcelike = []; for (const t of nonNulls) { if (typeList.length !== 0) { typeList.push(", "); } + typeList.push( this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: false, - inJsonNamespace: ctx.inJsonNamespace + inJsonNamespace: ctx.inJsonNamespace, }, withIssues, false, - false - ) + false, + ), ); } + return [this._variantType, "<", typeList, ">"]; } - protected variantType(u: UnionType, inJsonNamespace: boolean): Sourcelike { + protected variantType (u: UnionType, inJsonNamespace: boolean): Sourcelike { const [maybeNull, nonNulls] = removeNullFromUnion(u, true); assert(nonNulls.size >= 2, "Variant not needed for less than two types."); const indirection = maybeNull !== null; @@ -934,36 +978,37 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: !indirection, needsOptionalIndirection: !indirection, - inJsonNamespace + inJsonNamespace, }, true, - false + false, ); if (!indirection) { return variant; } + return [this.optionalType(u), "<", variant, ">"]; } - protected ourQualifier(inJsonNamespace: boolean): Sourcelike { + protected ourQualifier (inJsonNamespace: boolean): Sourcelike { return inJsonNamespace ? [arrayIntercalate("::", this._namespaceNames), "::"] : []; } - protected jsonQualifier(inJsonNamespace: boolean): Sourcelike { + protected jsonQualifier (inJsonNamespace: boolean): Sourcelike { return inJsonNamespace ? [] : "nlohmann::"; } - protected variantIndirection(type: Type, needIndirection: boolean, typeSrc: Sourcelike): Sourcelike { + protected variantIndirection (type: Type, needIndirection: boolean, typeSrc: Sourcelike): Sourcelike { if (!needIndirection) return typeSrc; return [this.optionalType(type), "<", typeSrc, ">"]; } - protected cppType( + protected cppType ( t: Type, ctx: TypeContext, withIssues: boolean, forceNarrowString: boolean, - isOptional: boolean + isOptional: boolean, ): Sourcelike { const inJsonNamespace = ctx.inJsonNamespace; if (isOptional && t instanceof UnionType) { @@ -975,20 +1020,21 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } } + const typeSource = matchType( t, _anyType => { isOptional = false; return maybeAnnotated(withIssues, anyTypeIssueAnnotation, [ this.jsonQualifier(inJsonNamespace), - "json" + "json", ]); }, _nullType => { isOptional = false; return maybeAnnotated(withIssues, nullTypeIssueAnnotation, [ this.jsonQualifier(inJsonNamespace), - "json" + "json", ]); }, _boolType => "bool", @@ -1008,25 +1054,26 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: true, - inJsonNamespace + inJsonNamespace, }, withIssues, forceNarrowString, - false + false, ), - ">" + ">", ], classType => this.variantIndirection( classType, ctx.needsForwardIndirection && this.isForwardDeclaredType(classType) && !isOptional, - [this.ourQualifier(inJsonNamespace), this.nameForNamedType(classType)] + [this.ourQualifier(inJsonNamespace), this.nameForNamedType(classType)], ), mapType => { let keyType = this._stringType.getType(); if (forceNarrowString) { keyType = "std::string"; } + return [ "std::map<", keyType, @@ -1036,13 +1083,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: true, - inJsonNamespace + inJsonNamespace, }, withIssues, forceNarrowString, - false + false, ), - ">" + ">", ]; }, enumType => [this.ourQualifier(inJsonNamespace), this.nameForNamedType(enumType)], @@ -1055,16 +1102,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace + inJsonNamespace, }, withIssues, forceNarrowString, - false + false, ); } else { return [this.ourQualifier(inJsonNamespace), this.nameForNamedType(unionType)]; } - } + }, ); if (!isOptional) return typeSource; return [this.optionalType(t), "<", typeSource, ">"]; @@ -1074,7 +1121,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { * similar to cppType, it practically gathers all the generated types within * 't'. It also records, whether a given sub-type is part of a variant or not. */ - protected generatedTypes(isClassMember: boolean, theType: Type): TypeRecord[] { + protected generatedTypes (isClassMember: boolean, theType: Type): TypeRecord[] { const result: TypeRecord[] = []; const recur = (forceInclude: boolean, isVariant: boolean, l: number, t: Type) => { if (t instanceof ArrayType) { @@ -1085,7 +1132,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude + forceInclude, }); } else if (t instanceof MapType) { recur(true, isVariant, l + 1, t.values); @@ -1095,7 +1142,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude: false + forceInclude: false, }); } else if (t instanceof UnionType) { /** @@ -1119,7 +1166,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { type: t, level: l, variant: true, - forceInclude + forceInclude, }); /** intentional "fall-through", add all subtypes as well - but forced include */ } @@ -1132,19 +1179,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } }; + recur(false, false, 0, theType); return result; } - protected constraintMember(jsonName: string): string { + protected constraintMember (jsonName: string): string { return this._memberNameStyle(`${jsonName}Constraint`); } - protected emitMember(cppType: Sourcelike, name: Sourcelike): void { + protected emitMember (cppType: Sourcelike, name: Sourcelike): void { this.emitLine(cppType, " ", name, ";"); } - protected emitClassMembers(c: ClassType, constraints: Map | undefined): void { + protected emitClassMembers (c: ClassType, constraints: Map | undefined): void { if (this._options.codeFormat) { this.emitLine("private:"); @@ -1155,13 +1203,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - property.isOptional + property.isOptional, ), - name + name, ); if (constraints?.has(jsonName)) { /** FIXME!!! NameStyle will/can collide with other Names */ @@ -1183,28 +1231,28 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - property.isOptional + property.isOptional, ), - name + name, ); } else { const [getterName, mutableGetterName, setterName] = defined( - this._gettersAndSettersForPropertyName.get(name) + this._gettersAndSettersForPropertyName.get(name), ); const rendered = this.cppType( property.type, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - property.isOptional + property.isOptional, ); /** @@ -1214,8 +1262,8 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { */ const checkConst = this.lookupGlobalName(GlobalNames.CheckConstraint); if ( - (property.type instanceof UnionType && property.type.findMember("null") !== undefined) || - (property.isOptional && property.type.kind !== "null" && property.type.kind !== "any") + property.type instanceof UnionType && property.type.findMember("null") !== undefined || + property.isOptional && property.type.kind !== "null" && property.type.kind !== "any" ) { this.emitLine(rendered, " ", getterName, "() const { return ", name, "; }"); if (constraints?.has(jsonName)) { @@ -1232,7 +1280,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.constraintMember(jsonName), ", *value); this->", name, - " = value; }" + " = value; }", ); } else { this.emitLine("void ", setterName, "(", rendered, " value) { this->", name, " = value; }"); @@ -1254,7 +1302,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.constraintMember(jsonName), ", value); this->", name, - " = value; }" + " = value; }", ); } else { this.emitLine( @@ -1264,16 +1312,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(rendered), " & value) { this->", name, - " = value; }" + " = value; }", ); } } + this.ensureBlankLine(); } }); } - protected generateClassConstraints(c: ClassType): Map | undefined { + protected generateClassConstraints (c: ClassType): Map | undefined { const res: Map = new Map(); this.forEachClassProperty(c, "none", (_name, jsonName, property) => { const constraints = constraintsForType(property.type); @@ -1286,11 +1335,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - property.isOptional + property.isOptional, ); res.set(jsonName, [ @@ -1311,19 +1360,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { pattern === undefined ? this._nulloptType : [ - this._stringType.getType(), - "(", - this._stringType.createStringLiteral([stringEscape(pattern)]), - ")" - ], - ")" + this._stringType.getType(), + "(", + this._stringType.createStringLiteral([stringEscape(pattern)]), + ")", + ], + ")", ]); }); return res.size === 0 ? undefined : res; } - protected emitClass(c: ClassType, className: Name): void { + protected emitClass (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitBlock([this._options.codeFormat ? "class " : "struct ", className], true, () => { const constraints = this.generateClassConstraints(c); @@ -1355,7 +1404,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } - protected emitTopLevelHeaders(t: Type, className: Name): void { + protected emitTopLevelHeaders (t: Type, className: Name): void { // Forward declarations for std::map (need to convert UTF16 <-> UTF8) if (t instanceof MapType && this._stringType !== this.NarrowString) { const ourQualifier = this.ourQualifier(true); @@ -1368,21 +1417,21 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " & j, ", ourQualifier, className, - " & x);" + " & x);", ); this.emitLine("static void to_json(json & j, ", this.withConst([ourQualifier, className]), " & x);"); }); } } - protected emitClassHeaders(className: Name): void { + protected emitClassHeaders (className: Name): void { const ourQualifier = this.ourQualifier(false); this.emitLine("void from_json(", this.withConst("json"), " & j, ", ourQualifier, className, " & x);"); this.emitLine("void to_json(json & j, ", this.withConst([ourQualifier, className]), " & x);"); } - protected emitTopLevelFunction(t: Type, className: Name): void { + protected emitTopLevelFunction (t: Type, className: Name): void { // Function definitions for std::map (need to convert UTF16 <-> UTF8) if (t instanceof MapType && this._stringType !== this.NarrowString) { const ourQualifier = this.ourQualifier(true); @@ -1399,7 +1448,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " & j, ", ourQualifier, className, - "& x)" + "& x)", ], false, () => { @@ -1408,22 +1457,22 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, true, - false + false, ); toType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, false, - false + false, ); this.emitLine([ @@ -1431,11 +1480,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ "j.get<", cppType, - ">()" + ">()", ]), - ";" + ";", ]); - } + }, ); this.emitBlock( @@ -1445,7 +1494,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { className, ">::to_json(json & j, ", this.withConst([ourQualifier, className]), - " & x)" + " & x)", ], false, () => { @@ -1454,35 +1503,35 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, false, - false + false, ); toType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, true, - false + false, ); this.emitLine([ "j = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, "x"), - ";" + ";", ]); - } + }, ); } } - protected emitClassFunctions(c: ClassType, className: Name): void { + protected emitClassFunctions (c: ClassType, className: Name): void { const ourQualifier = this.ourQualifier(false); let cppType: Sourcelike; let toType: Sourcelike; @@ -1513,15 +1562,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(json)])] + [this._stringType.createStringLiteral([stringEscape(json)])], ), - ")" - ] + ")", + ], ), - ";" + ";", ); return; } + if (p.isOptional || propType instanceof UnionType) { const [nullOrOptional, typeSet] = (function (): [boolean, ReadonlySet] { if (propType instanceof UnionType) { @@ -1539,20 +1589,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: false + inJsonNamespace: false, }, false, - true + true, ); toType = this.cppTypeInOptional( typeSet, { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: false + inJsonNamespace: false, }, false, - false + false, ); this.emitLine( assignment.wrap( @@ -1571,39 +1621,40 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(json)])] + [this._stringType.createStringLiteral([stringEscape(json)])], ), - ")" - ] - ) - ] + ")", + ], + ), + ], ), - ";" + ";", ); return; } } + cppType = this.cppType( propType, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, false, true, - p.isOptional + p.isOptional, ); toType = this.cppType( propType, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, false, false, - p.isOptional + p.isOptional, ); this.emitLine( assignment.wrap( @@ -1614,17 +1665,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - this._stringType.createStringLiteral([stringEscape(json)]) + this._stringType.createStringLiteral([stringEscape(json)]), ), ").get<", cppType, - ">()" - ]) + ">()", + ]), ), - ";" + ";", ); }); - } + }, ); this.ensureBlankLine(); @@ -1640,22 +1691,22 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, false, false, - p.isOptional + p.isOptional, ); toType = this.cppType( propType, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, false, true, - p.isOptional + p.isOptional, ); const [getterName, ,] = defined(this._gettersAndSettersForPropertyName.get(name)); let getter: Sourcelike[]; @@ -1664,39 +1715,40 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } else { getter = [name]; } + const assignment: Sourcelike[] = [ "j[", this._stringType.wrapEncodingChange( [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - this._stringType.createStringLiteral([stringEscape(json)]) + this._stringType.createStringLiteral([stringEscape(json)]), ), "] = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, ["x.", getter]), - ";" + ";", ]; if (p.isOptional && this._options.hideNullOptional) { this.emitBlock( [ "if (", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, ["x.", getter]), - ")" + ")", ], false, () => { this.emitLine(assignment); - } + }, ); } else { this.emitLine(assignment); } }); - } + }, ); } - protected emitEnum(e: EnumType, enumName: Name): void { + protected emitEnum (e: EnumType, enumName: Name): void { const caseNames: Sourcelike[] = []; const enumValues = enumCaseValues(e, this.targetLanguage.name); @@ -1715,11 +1767,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("enum class ", enumName, " : ", this._enumType, " { ", caseNames, " };"); } - protected emitUnionTypedefs(u: UnionType, unionName: Name): void { + protected emitUnionTypedefs (u: UnionType, unionName: Name): void { this.emitLine("using ", unionName, " = ", this.variantType(u, false), ";"); } - protected emitUnionHeaders(u: UnionType): void { + protected emitUnionHeaders (u: UnionType): void { // Forward declarations for boost::variant. If none of the Ts were defined by us (e.g. if we have // boost::variant) then we need to specialize nlohmann::adl_serializer for our // variant type. If at least one of the Ts is our type then we could get away with regular adl definitions, @@ -1732,10 +1784,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false + false, ); this.emitLine("template <>"); @@ -1745,12 +1797,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } - protected emitUnionFunctions(u: UnionType): void { + protected emitUnionFunctions (u: UnionType): void { // Function definitions for boost::variant. const ourQualifier = this.ourQualifier(true) as string; - const functionForKind: [string, string][] = [ + const functionForKind: Array<[string, string]> = [ ["bool", "is_boolean"], ["integer", "is_number_integer"], ["double", "is_number"], @@ -1758,7 +1810,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ["class", "is_object"], ["map", "is_object"], ["array", "is_array"], - ["enum", "is_string"] + ["enum", "is_string"], ]; const nonNulls = removeNullFromUnion(u, true)[1]; const variantType = this.cppTypeInOptional( @@ -1766,10 +1818,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false + false, ); this.emitBlock( @@ -1780,7 +1832,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst("json"), " & j, ", variantType, - " & x)" + " & x)", ], false, () => { @@ -1795,37 +1847,38 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, true, - false + false, ); const toType = this.cppType( typeForKind, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, false, - false + false, ); this.emitLine( "x = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ "j.get<", cppType, - ">()" + ">()", ]), - ";" + ";", ); }); onFirst = false; } - this.emitLine('else throw std::runtime_error("Could not deserialise!");'); - } + + this.emitLine("else throw std::runtime_error(\"Could not deserialise!\");"); + }, ); this.ensureBlankLine(); @@ -1843,56 +1896,57 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, false, - false + false, ); const toType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, true, - false + false, ); this.emitLine( "j = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ this._options.boost ? "boost::get<" : "std::get<", cppType, - ">(x)" + ">(x)", ]), - ";" + ";", ); this.emitLine("break;"); }); i++; } - this.emitLine('default: throw std::runtime_error("Input JSON does not conform to schema!");'); + + this.emitLine("default: throw std::runtime_error(\"Input JSON does not conform to schema!\");"); }); - } + }, ); } - protected emitEnumHeaders(enumName: Name): void { + protected emitEnumHeaders (enumName: Name): void { const ourQualifier = this.ourQualifier(false); this.emitLine("void from_json(", this.withConst("json"), " & j, ", ourQualifier, enumName, " & x);"); this.emitLine("void to_json(json & j, ", this.withConst([ourQualifier, enumName]), " & x);"); } - private isLargeEnum(e: EnumType) { + private isLargeEnum (e: EnumType) { // This is just an estimation. Someone might want to do some // benchmarks to find the optimum value here return e.cases.size > 15; } - protected emitEnumFunctions(e: EnumType, enumName: Name): void { + protected emitEnumFunctions (e: EnumType, enumName: Name): void { const ourQualifier = this.ourQualifier(false); this.emitBlock( @@ -1907,7 +1961,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ", ", ourQualifier, enumName, - "> enumValues" + "> enumValues", ], true, () => { @@ -1918,17 +1972,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(jsonName)])] + [this._stringType.createStringLiteral([stringEscape(jsonName)])], ), ", ", ourQualifier, enumName, "::", name, - "}," + "},", ); }); - } + }, ); this.emitLine(`auto iter = enumValues.find(j.get<${this._stringType.getType()}>());`); @@ -1946,20 +2000,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(jsonName)])] + [this._stringType.createStringLiteral([stringEscape(jsonName)])], ), ") x = ", ourQualifier, enumName, "::", name, - ";" + ";", ); onFirst = false; }); - this.emitLine('else { throw std::runtime_error("Input JSON does not conform to schema!"); }'); + this.emitLine("else { throw std::runtime_error(\"Input JSON does not conform to schema!\"); }"); } - } + }, ); this.ensureBlankLine(); @@ -1980,20 +2034,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(jsonName)])] + [this._stringType.createStringLiteral([stringEscape(jsonName)])], ), - "; break;" + "; break;", ); }); this.emitLine( - `default: throw std::runtime_error("Unexpected value in enumeration \\"${enumName}\\": " + std::to_string(static_cast(x)));` + `default: throw std::runtime_error("Unexpected value in enumeration \\"${enumName}\\": " + std::to_string(static_cast(x)));`, ); }); - } + }, ); } - protected emitTopLevelTypedef(t: Type, name: Name): void { + protected emitTopLevelTypedef (t: Type, name: Name): void { this.emitLine( "using ", name, @@ -2003,17 +2057,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - false + false, ), - ";" + ";", ); } - protected emitAllUnionFunctions(): void { + protected emitAllUnionFunctions (): void { this.forEachUniqueUnion( "leading-and-interposing", u => @@ -2023,17 +2077,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false - ) + false, + ), ), - (u: UnionType) => this.emitUnionFunctions(u) + (u: UnionType) => this.emitUnionFunctions(u), ); } - protected emitAllUnionHeaders(): void { + protected emitAllUnionHeaders (): void { this.forEachUniqueUnion( "interposing", u => @@ -2043,17 +2097,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false - ) + false, + ), ), - (u: UnionType) => this.emitUnionHeaders(u) + (u: UnionType) => this.emitUnionHeaders(u), ); } - protected emitOptionalHelpers(): void { + protected emitOptionalHelpers (): void { this.emitLine("#ifndef NLOHMANN_OPT_HELPER"); this.emitLine("#define NLOHMANN_OPT_HELPER"); @@ -2066,7 +2120,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.emitLine("if (!opt) j = nullptr; else j = *opt;"); - } + }, ); this.ensureBlankLine(); @@ -2076,12 +2130,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.emitLine( - `if (j.is_null()) return ${factory}(); else return ${factory}(j.get());` + `if (j.is_null()) return ${factory}(); else return ${factory}(j.get());`, ); - } + }, ); }); }; + emitAdlStruct(this.optionalTypeHeap(), this.optionalFactoryHeap()); emitAdlStruct(this.optionalTypeStack(), this.optionalFactoryStack()); }); @@ -2089,7 +2144,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("#endif"); } - protected emitDeclaration(decl: Declaration): void { + protected emitDeclaration (decl: Declaration): void { if (decl.kind === "forward") { if (this._options.codeFormat) { this.emitLine("class ", this.nameForNamedType(decl.type), ";"); @@ -2113,17 +2168,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitGetterSetter(t: string, getterName: string, setterName: string, memberName: string): void { + protected emitGetterSetter (t: string, getterName: string, setterName: string, memberName: string): void { this.emitLine("void ", setterName, "(", t, " ", memberName, ") { this->", memberName, " = ", memberName, "; }"); this.emitLine("auto ", getterName, "() const { return ", memberName, "; }"); } - protected emitNumericCheckConstraints( + protected emitNumericCheckConstraints ( checkConst: string, classConstraint: string, getterMinValue: string, getterMaxValue: string, - cppType: string + cppType: string, ): void { this.emitBlock( [ @@ -2135,7 +2190,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(classConstraint), " & c, ", cppType, - " value)" + " value)", ], false, () => { @@ -2158,9 +2213,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMinValue, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); @@ -2183,17 +2238,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMaxValue, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); - } + }, ); this.ensureBlankLine(); } - protected emitConstraintClasses(): void { + protected emitConstraintClasses (): void { const ourQualifier = this.ourQualifier(false) as string; const getterMinIntValue = this.lookupMemberName(MemberNames.GetMinIntValue); @@ -2211,6 +2266,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { for (const member of constraintMembers) { this.emitMember([this._optionalType, "<", member.cppType, ">"], this.lookupMemberName(member.name)); } + this.ensureBlankLine(); this.emitLine("public:"); this.emitLine(classConstraint, "("); @@ -2235,7 +2291,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { withDefault(member.cppConstType, member.cppType), this.lookupMemberName(member.getter), this.lookupMemberName(member.setter), - this.lookupMemberName(member.name) + this.lookupMemberName(member.name), ); } }); @@ -2253,9 +2309,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - ["msg"] + ["msg"], ), - ") {}" + ") {}", ); }); this.ensureBlankLine(); @@ -2265,7 +2321,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { GlobalNames.ValueTooHighException, GlobalNames.ValueTooShortException, GlobalNames.ValueTooLongException, - GlobalNames.InvalidPatternException + GlobalNames.InvalidPatternException, ]; for (const ex of exceptions) { @@ -2284,7 +2340,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { classConstraint, getterMinDoubleValue, getterMaxDoubleValue, - "double" + "double", ); this.emitBlock( @@ -2297,7 +2353,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(classConstraint), " & c, ", this._stringType.getConstType(), - " value)" + " value)", ], false, () => { @@ -2309,7 +2365,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._nulloptType, " && value.length() < *c.", getterMinLength, - "())" + "())", ], false, () => { @@ -2328,9 +2384,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMinLength, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); @@ -2342,7 +2398,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._nulloptType, " && value.length() > *c.", getterMaxLength, - "())" + "())", ], false, () => { @@ -2361,9 +2417,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMaxLength, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); @@ -2374,7 +2430,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.getRegex(), "( *c.", getterPattern, - "() ));" + "() ));", ); this.emitBlock(["if (result.empty())"], false, () => { this.emitLine( @@ -2390,16 +2446,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { getterPattern, "() + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); }); }); this.ensureBlankLine(); - } + }, ); } - protected emitHelperFunctions(): void { + protected emitHelperFunctions (): void { this._stringType.emitHelperFunctions(); if ( @@ -2437,7 +2493,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("return j.at(property).get();"); }); this.emitLine("return json();"); - } + }, ); this.ensureBlankLine(); @@ -2447,7 +2503,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.emitLine("return get_untyped(j, property.data());"); - } + }, ); this.emitLine("#endif"); @@ -2470,7 +2526,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst("json"), " & j, ", this.withConst("char"), - " * property)" + " * property)", ], false, () => { @@ -2479,7 +2535,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("return j.at(property).get<", optionalType, ">();"); }); this.emitLine("return ", optionalType, "();"); - } + }, ); this.ensureBlankLine(); @@ -2491,14 +2547,15 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { optionalType, ` get_${label}_optional(`, this.withConst("json"), - " & j, std::string property)" + " & j, std::string property)", ], false, () => { this.emitLine(`return get_${label}_optional(j, property.data());`); - } + }, ); }; + emitGetOptional(this.optionalTypeHeap(), "heap"); emitGetOptional(this.optionalTypeStack(), "stack"); @@ -2508,7 +2565,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitExtraIncludes(): void { + protected emitExtraIncludes (): void { this.ensureBlankLine(); if (this._options.codeFormat) { @@ -2517,6 +2574,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } else { this.emitInclude(true, "optional"); } + this.emitInclude(true, "stdexcept"); this.emitInclude(true, "regex"); } @@ -2534,7 +2592,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitHelper(): void { + protected emitHelper (): void { this.startFile("helper.hpp", false); this.emitExtraIncludes(); @@ -2555,35 +2613,36 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.finishFile(); } - protected emitTypes(): void { + protected emitTypes (): void { if (!this._options.justTypes) { this.emitLine("using nlohmann::json;"); this.ensureBlankLine(); this.emitHelperFunctions(); } + this.forEachDeclaration("interposing", decl => this.emitDeclaration(decl)); if (this._options.justTypes) return; this.forEachTopLevel( "leading", (t: Type, name: Name) => this.emitTopLevelTypedef(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); } - protected gatherUserNamespaceForwardDecls(): Sourcelike[] { + protected gatherUserNamespaceForwardDecls (): Sourcelike[] { return this.gatherSource(() => { this.forEachObject("leading-and-interposing", (_: any, className: Name) => - this.emitClassHeaders(className) + this.emitClassHeaders(className), ); this.forEachEnum("leading-and-interposing", (_: any, enumName: Name) => this.emitEnumHeaders(enumName)); }); } - protected gatherNlohmannNamespaceForwardDecls(): Sourcelike[] { + protected gatherNlohmannNamespaceForwardDecls (): Sourcelike[] { return this.gatherSource(() => { this.forEachTopLevel("leading-and-interposing", (t: Type, className: Name) => - this.emitTopLevelHeaders(t, className) + this.emitTopLevelHeaders(t, className), ); this.ensureBlankLine(); @@ -2592,21 +2651,21 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } - protected emitUserNamespaceImpls(): void { + protected emitUserNamespaceImpls (): void { this.forEachObject("leading-and-interposing", (c: ClassType, className: Name) => - this.emitClassFunctions(c, className) + this.emitClassFunctions(c, className), ); this.forEachEnum("leading-and-interposing", (e: EnumType, enumName: Name) => - this.emitEnumFunctions(e, enumName) + this.emitEnumFunctions(e, enumName), ); } - protected emitNlohmannNamespaceImpls(): void { + protected emitNlohmannNamespaceImpls (): void { this.forEachTopLevel( "leading-and-interposing", (t: Type, name: Name) => this.emitTopLevelFunction(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); this.ensureBlankLine(); @@ -2614,7 +2673,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitAllUnionFunctions(); } - protected emitGenerators(): void { + protected emitGenerators (): void { if (this._options.justTypes) { let didEmit = false; const gathered = this.gatherSource(() => @@ -2622,9 +2681,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { didEmit = this.forEachTopLevel( "none", (t: Type, name: Name) => this.emitTopLevelTypedef(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); - }) + }), ); if (didEmit) { this.emitGatheredSource(gathered); @@ -2661,7 +2720,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitSingleSourceStructure(proposedFilename: string): void { + protected emitSingleSourceStructure (proposedFilename: string): void { this.startFile(proposedFilename); this._generatedFiles.add(proposedFilename); @@ -2674,6 +2733,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitOptionalHelpers(); this.ensureBlankLine(); } + this.emitNamespaces(this._namespaceNames, () => this.emitTypes()); } @@ -2684,7 +2744,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.finishFile(); } - protected updateIncludes(isClassMember: boolean, includes: IncludeMap, propertyType: Type, _defName: string): void { + protected updateIncludes (isClassMember: boolean, includes: IncludeMap, propertyType: Type, _defName: string): void { const propTypes = this.generatedTypes(isClassMember, propertyType); for (const t of propTypes) { @@ -2737,7 +2797,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitIncludes(c: ClassType | UnionType | EnumType, defName: string): void { + protected emitIncludes (c: ClassType | UnionType | EnumType, defName: string): void { /** * Need to generate "includes", in terms 'c' has members, which * are defined by others @@ -2804,7 +2864,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitDefinition(d: ClassType | EnumType | UnionType, defName: Name): void { + protected emitDefinition (d: ClassType | EnumType | UnionType, defName: Name): void { const name = `${this.sourcelikeToString(defName)}.hpp`; this.startFile(name, true); this._generatedFiles.add(name); @@ -2828,7 +2888,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.finishFile(); } - protected emitMultiSourceStructure(proposedFilename: string): void { + protected emitMultiSourceStructure (proposedFilename: string): void { if (!this._options.justTypes && this.haveNamedTypes) { this.emitHelper(); @@ -2854,7 +2914,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }, (u, n) => { this.emitDefinition(u, n); - } + }, ); /** @@ -2876,7 +2936,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading", (t: Type, name: Name) => this.emitTopLevelTypedef(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); }); @@ -2884,7 +2944,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitSourceStructure(proposedFilename: string): void { + protected emitSourceStructure (proposedFilename: string): void { this._generatedFiles.clear(); /** Gather all the unique/custom types used by the schema */ @@ -2899,13 +2959,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - false - ) - ) + false, + ), + ), ]); } @@ -2922,17 +2982,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected isConversionRequired(t: Type) { + protected isConversionRequired (t: Type) { const originalType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, false, - false + false, ); const newType = this.cppType( @@ -2940,18 +3000,18 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, true, - false + false, ); return originalType !== newType; } - public NarrowString = new (class extends BaseString implements StringType { - constructor() { + public NarrowString = new class extends BaseString implements StringType { + constructor () { super( "std::string", "const std::string & ", @@ -2960,26 +3020,26 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { "", new WrappingCode(["std::to_string("], [")"]), "", - "" + "", ); } - public wrapEncodingChange( + public wrapEncodingChange ( _qualifier: Sourcelike[], _fromType: Sourcelike, _toType: Sourcelike, - inner: Sourcelike + inner: Sourcelike, ): Sourcelike { return inner; } - public emitHelperFunctions(): void { + public emitHelperFunctions (): void { return; } - })(); + }(); - public WideString = new (class extends BaseString implements StringType { - constructor(public superThis: CPlusPlusRenderer) { + public WideString = new class extends BaseString implements StringType { + constructor (public superThis: CPlusPlusRenderer) { super( "std::wstring", "const std::wstring & ", @@ -2988,15 +3048,15 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { "L", new WrappingCode(["std::to_wstring("], [")"]), "Utf16_Utf8", - "convert" + "convert", ); } - public wrapEncodingChange( + public wrapEncodingChange ( qualifier: Sourcelike[], fromType: Sourcelike, toType: Sourcelike, - inner: Sourcelike + inner: Sourcelike, ): Sourcelike { if (this.superThis.sourcelikeToString(fromType) === this.superThis.sourcelikeToString(toType)) { return inner; @@ -3012,11 +3072,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._encodingFunction, "(", inner, - ")" + ")", ]; } - public emitHelperFunctions(): void { + public emitHelperFunctions (): void { this.superThis.emitLine("template"); this.superThis.emitLine("struct tag {};"); this.superThis.ensureBlankLine(); @@ -3030,9 +3090,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.superThis.emitLine( - "if (ptr == nullptr) return std::unique_ptr(); else return std::unique_ptr(new TT(Utf16_Utf8::convert(*ptr)));" + "if (ptr == nullptr) return std::unique_ptr(); else return std::unique_ptr(new TT(Utf16_Utf8::convert(*ptr)));", ); - } + }, ); this.superThis.ensureBlankLine(); @@ -3048,7 +3108,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.superThis.emitLine("it++;"); }); this.superThis.emitLine("return newVector;"); - } + }, ); this.superThis.ensureBlankLine(); @@ -3061,12 +3121,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.superThis.emitLine("auto newMap = std::map();"); this.superThis.emitBlock(["while (it != m.end())"], false, () => { this.superThis.emitLine( - "newMap.insert(std::pair(Utf16_Utf8::convert(it->first), Utf16_Utf8::convert(it->second)));" + "newMap.insert(std::pair(Utf16_Utf8::convert(it->first), Utf16_Utf8::convert(it->second)));", ); this.superThis.emitLine("it++;"); }); this.superThis.emitLine("return newMap;"); - } + }, ); this.superThis.ensureBlankLine(); @@ -3081,9 +3141,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.superThis.emitLine( - "return std::wstring_convert, wchar_t>{}.from_bytes(str.data());" + "return std::wstring_convert, wchar_t>{}.from_bytes(str.data());", ); - } + }, ); this.superThis.ensureBlankLine(); @@ -3092,9 +3152,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.superThis.emitLine( - "return std::wstring_convert, wchar_t>{}.to_bytes(str.data());" + "return std::wstring_convert, wchar_t>{}.to_bytes(str.data());", ); - } + }, ); this.superThis.ensureBlankLine(); @@ -3112,10 +3172,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.superThis.emitLine( "return ", this.superThis.ourQualifier(false), - "Utf16_Utf8::convert(s.str()); " + "Utf16_Utf8::convert(s.str()); ", ); }); this.superThis.ensureBlankLine(); } - })(this); + }(this); } diff --git a/packages/quicktype-core/src/language/CSharp.ts b/packages/quicktype-core/src/language/CSharp.ts index 627e387be..9ffc68669 100644 --- a/packages/quicktype-core/src/language/CSharp.ts +++ b/packages/quicktype-core/src/language/CSharp.ts @@ -1,18 +1,24 @@ import { arrayIntercalate } from "collection-utils"; import { - Type, + type Type, + type ClassProperty, + type TransformedStringTypeKind, + type PrimitiveStringTypeKind, + type PrimitiveType, +} from "../Type"; +import { EnumType, UnionType, ClassType, - ClassProperty, ArrayType, - TransformedStringTypeKind, - PrimitiveStringTypeKind, - PrimitiveType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion, directlyReachableSingleNamedType } from "../TypeUtils"; -import { Sourcelike, maybeAnnotated, modifySource } from "../Source"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated, modifySource } from "../Source"; +import { + type WordInName, +} from "../support/Strings"; import { utf16LegalizeCharacters, utf16StringEscape, @@ -20,19 +26,23 @@ import { combineWords, firstUpperWordStyle, camelCase, - WordInName } from "../support/Strings"; import { defined, assert, panic, assertNever } from "../support/Support"; -import { Name, DependencyName, Namer, funPrefixNamer, SimpleName } from "../Naming"; -import { ConvenienceRenderer, ForbiddenWordsInfo, inferredNameOrder } from "../ConvenienceRenderer"; +import { type Name, type Namer} from "../Naming"; +import { DependencyName, funPrefixNamer, SimpleName } from "../Naming"; +import { type ForbiddenWordsInfo} from "../ConvenienceRenderer"; +import { ConvenienceRenderer, inferredNameOrder } from "../ConvenienceRenderer"; import { TargetLanguage } from "../TargetLanguage"; -import { StringOption, EnumOption, Option, BooleanOption, OptionValues, getOptionValues } from "../RendererOptions"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { StringOption, EnumOption, BooleanOption, getOptionValues } from "../RendererOptions"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { StringTypeMapping } from "../TypeBuilder"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { + type Transformer, + type Transformation} from "../Transformers"; import { followTargetType, transformationForType, - Transformer, DecodingTransformer, DecodingChoiceTransformer, UnionInstantiationTransformer, @@ -43,13 +53,12 @@ import { StringProducerTransformer, ParseStringTransformer, StringifyTransformer, - Transformation, ArrayDecodingTransformer, ArrayEncodingTransformer, MinMaxLengthCheckTransformer, - MinMaxValueTransformer + MinMaxValueTransformer, } from "../Transformers"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; import { minMaxLengthForType, minMaxValueForType } from "../attributes/Constraints"; import unicode from "unicode-properties"; @@ -59,7 +68,9 @@ export enum Framework { } export type Version = 5 | 6; -export type OutputFeatures = { helpers: boolean; attributes: boolean }; +export interface OutputFeatures { + attributes: boolean; helpers: boolean; +} export enum AccessModifier { None, @@ -69,32 +80,35 @@ export enum AccessModifier { export type CSharpTypeForAny = "object" | "dynamic"; -function noFollow(t: Type): Type { +function noFollow (t: Type): Type { return t; } -function needTransformerForType(t: Type): "automatic" | "manual" | "nullable" | "none" { +function needTransformerForType (t: Type): "automatic" | "manual" | "nullable" | "none" { if (t instanceof UnionType) { const maybeNullable = nullableFromUnion(t); if (maybeNullable === null) return "automatic"; if (needTransformerForType(maybeNullable) === "manual") return "nullable"; return "none"; } + if (t instanceof ArrayType) { const itemsNeed = needTransformerForType(t.items); if (itemsNeed === "manual" || itemsNeed === "nullable") return "automatic"; return "none"; } + if (t instanceof EnumType) return "automatic"; if (t.kind === "double") return minMaxValueForType(t) !== undefined ? "manual" : "none"; if (t.kind === "integer-string" || t.kind === "bool-string") return "manual"; if (t.kind === "string") { return minMaxLengthForType(t) !== undefined ? "manual" : "none"; } + return "none"; } -function alwaysApplyTransformation(xf: Transformation): boolean { +function alwaysApplyTransformation (xf: Transformation): boolean { const t = xf.targetType; if (t instanceof EnumType) return true; if (t instanceof UnionType) return nullableFromUnion(t) === null; @@ -104,7 +118,7 @@ function alwaysApplyTransformation(xf: Transformation): boolean { /** * The C# type for a given transformed string type. */ -function csTypeForTransformedStringType(t: PrimitiveType): Sourcelike { +function csTypeForTransformedStringType (t: PrimitiveType): Sourcelike { switch (t.kind) { case "date-time": return "DateTimeOffset"; @@ -123,23 +137,23 @@ export const cSharpOptions = { "Serialization framework", [ ["NewtonSoft", Framework.Newtonsoft], - ["SystemTextJson", Framework.SystemTextJson] + ["SystemTextJson", Framework.SystemTextJson], ], - "NewtonSoft" + "NewtonSoft", ), useList: new EnumOption("array-type", "Use T[] or List", [ ["array", false], - ["list", true] + ["list", true], ]), dense: new EnumOption( "density", "Property density", [ ["normal", false], - ["dense", true] + ["dense", true], ], "normal", - "secondary" + "secondary", ), // FIXME: Do this via a configurable named eventually. namespace: new StringOption("namespace", "Generated namespace", "NAME", "QuickType"), @@ -148,58 +162,58 @@ export const cSharpOptions = { "C# version", [ ["5", 5], - ["6", 6] + ["6", 6], ], "6", - "secondary" + "secondary", ), virtual: new BooleanOption("virtual", "Generate virtual properties", false), typeForAny: new EnumOption( "any-type", - 'Type to use for "any"', + "Type to use for \"any\"", [ ["object", "object"], - ["dynamic", "dynamic"] + ["dynamic", "dynamic"], ], "object", - "secondary" + "secondary", ), useDecimal: new EnumOption( "number-type", "Type to use for numbers", [ ["double", false], - ["decimal", true] + ["decimal", true], ], "double", - "secondary" + "secondary", ), features: new EnumOption("features", "Output features", [ ["complete", { namespaces: true, helpers: true, attributes: true }], ["attributes-only", { namespaces: true, helpers: false, attributes: true }], ["just-types-and-namespace", { namespaces: true, helpers: false, attributes: false }], - ["just-types", { namespaces: true, helpers: false, attributes: false }] + ["just-types", { namespaces: true, helpers: false, attributes: false }], ]), baseclass: new EnumOption( "base-class", "Base class", [ ["EntityData", "EntityData"], - ["Object", undefined] + ["Object", undefined], ], "Object", - "secondary" + "secondary", ), checkRequired: new BooleanOption("check-required", "Fail if required properties are missing", false), - keepPropertyName: new BooleanOption("keep-property-name", "Keep original field name generate", false) + keepPropertyName: new BooleanOption("keep-property-name", "Keep original field name generate", false), }; export class CSharpTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("C#", ["cs", "csharp"], "cs"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ cSharpOptions.framework, cSharpOptions.namespace, @@ -212,11 +226,11 @@ export class CSharpTargetLanguage extends TargetLanguage { cSharpOptions.features, cSharpOptions.baseclass, cSharpOptions.checkRequired, - cSharpOptions.keepPropertyName + cSharpOptions.keepPropertyName, ]; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date-time"); mapping.set("time", "date-time"); @@ -228,22 +242,22 @@ export class CSharpTargetLanguage extends TargetLanguage { return mapping; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - needsTransformerForType(t: Type): boolean { + needsTransformerForType (t: Type): boolean { const need = needTransformerForType(t); return need !== "none" && need !== "nullable"; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): ConvenienceRenderer { const options = getOptionValues(cSharpOptions, untypedOptionValues); @@ -252,13 +266,13 @@ export class CSharpTargetLanguage extends TargetLanguage { return new NewtonsoftCSharpRenderer( this, renderContext, - getOptionValues(newtonsoftCSharpOptions, untypedOptionValues) + getOptionValues(newtonsoftCSharpOptions, untypedOptionValues), ); case Framework.SystemTextJson: return new SystemTextJsonCSharpRenderer( this, renderContext, - getOptionValues(systemTextJsonCSharpOptions, untypedOptionValues) + getOptionValues(systemTextJsonCSharpOptions, untypedOptionValues), ); default: return assertNever(options.framework); @@ -274,24 +288,26 @@ const denseJsonPropertyName = "J"; const denseRequiredEnumName = "R"; const denseNullValueHandlingEnumName = "N"; -function isStartCharacter(utf16Unit: number): boolean { +function isStartCharacter (utf16Unit: number): boolean { if (unicode.isAlphabetic(utf16Unit)) { return true; } + return utf16Unit === 0x5f; // underscore } -function isPartCharacter(utf16Unit: number): boolean { +function isPartCharacter (utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - if (["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0) { + if (["Nd", "Pc", "Mn", "Mc"].includes(category)) { return true; } + return isStartCharacter(utf16Unit); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); -function csNameStyle(original: string): string { +function csNameStyle (original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -301,11 +317,11 @@ function csNameStyle(original: string): string { firstUpperWordStyle, firstUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } -function csNameStyleKeep(original: string): string { +function csNameStyleKeep (original: string): string { const keywords = [ "abstract", "as", @@ -383,14 +399,14 @@ function csNameStyleKeep(original: string): string { "virtual", "void", "volatile", - "while" + "while", ]; const words: WordInName[] = [ { word: original, - isAcronym: false - } + isAcronym: false, + }, ]; const result = combineWords( @@ -401,33 +417,34 @@ function csNameStyleKeep(original: string): string { x => x, x => x, "", - isStartCharacter + isStartCharacter, ); return keywords.includes(result) ? "@" + result : result; } -function isValueType(t: Type): boolean { +function isValueType (t: Type): boolean { if (t instanceof UnionType) { return nullableFromUnion(t) === null; } - return ["integer", "double", "bool", "enum", "date-time", "uuid"].indexOf(t.kind) >= 0; + + return ["integer", "double", "bool", "enum", "date-time", "uuid"].includes(t.kind); } export class CSharpRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _csOptions: OptionValues + private readonly _csOptions: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return ["QuickType", "Type", "System", "Console", "Exception", "DateTimeOffset", "Guid", "Uri"]; } - protected forbiddenForObjectProperties(_: ClassType, classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_: ClassType, classNamed: Name): ForbiddenWordsInfo { return { names: [ classNamed, @@ -437,54 +454,54 @@ export class CSharpRenderer extends ConvenienceRenderer { "Equals", "GetType", "MemberwiseClone", - "ReferenceEquals" + "ReferenceEquals", ], - includeGlobalForbidden: false + includeGlobalForbidden: false, }; } - protected forbiddenForUnionMembers(_: UnionType, unionNamed: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_: UnionType, unionNamed: Name): ForbiddenWordsInfo { return { names: [unionNamed], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return namingFunction; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return this._csOptions.keepPropertyName ? namingFunctionKeep : namingFunction; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return namingFunction; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return namingFunction; } - protected unionNeedsName(u: UnionType): boolean { + protected unionNeedsName (u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { // If the top-level type doesn't contain any classes or unions // we have to define a class just for the `FromJson` method, in // emitFromJsonForTopLevel. return directlyReachableSingleNamedType(type); } - protected emitBlock(f: () => void, semicolon = false): void { + protected emitBlock (f: () => void, semicolon = false): void { this.emitLine("{"); this.indent(f); this.emitLine("}", semicolon ? ";" : ""); } - protected get doubleType(): string { + protected get doubleType (): string { return this._csOptions.useDecimal ? "decimal" : "double"; } - protected csType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { + protected csType (t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { const actualType = follow(t); return matchType( actualType, @@ -510,11 +527,11 @@ export class CSharpRenderer extends ConvenienceRenderer { if (nullable !== null) return this.nullableCSType(nullable, noFollow); return this.nameForNamedType(unionType); }, - transformedStringType => csTypeForTransformedStringType(transformedStringType) + transformedStringType => csTypeForTransformedStringType(transformedStringType), ); } - protected nullableCSType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { + protected nullableCSType (t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { t = followTargetType(t); const csType = this.csType(t, follow, withIssues); if (isValueType(t)) { @@ -523,16 +540,18 @@ export class CSharpRenderer extends ConvenienceRenderer { return csType; } } - protected baseclassForType(_t: Type): Sourcelike | undefined { + + protected baseclassForType (_t: Type): Sourcelike | undefined { return undefined; } - protected emitType( + + protected emitType ( description: string[] | undefined, accessModifier: AccessModifier, declaration: Sourcelike, name: Sourcelike, baseclass: Sourcelike | undefined, - emitter: () => void + emitter: () => void, ): void { switch (accessModifier) { case AccessModifier.Public: @@ -544,25 +563,27 @@ export class CSharpRenderer extends ConvenienceRenderer { default: break; } + this.emitDescription(description); if (baseclass === undefined) { this.emitLine(declaration, " ", name); } else { this.emitLine(declaration, " ", name, " : ", baseclass); } + this.emitBlock(emitter); } - protected attributesForProperty( + protected attributesForProperty ( _property: ClassProperty, _name: Name, _c: ClassType, - _jsonName: string + _jsonName: string, ): Sourcelike[] | undefined { return undefined; } - protected propertyDefinition(property: ClassProperty, name: Name, _c: ClassType, _jsonName: string): Sourcelike { + protected propertyDefinition (property: ClassProperty, name: Name, _c: ClassType, _jsonName: string): Sourcelike { const t = property.type; const csType = property.isOptional ? this.nullableCSType(t, followTargetType, true) @@ -575,7 +596,7 @@ export class CSharpRenderer extends ConvenienceRenderer { return [...propertyArray, csType, " ", name, " { get; set; }"]; } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { const start = "/// "; if (this._csOptions.dense) { this.emitLine(start, lines.join("; "), ""); @@ -584,11 +605,11 @@ export class CSharpRenderer extends ConvenienceRenderer { } } - protected blankLinesBetweenAttributes(): boolean { + protected blankLinesBetweenAttributes (): boolean { return false; } - private emitClassDefinition(c: ClassType, className: Name): void { + private emitClassDefinition (c: ClassType, className: Name): void { this.emitType( this.descriptionForType(c), AccessModifier.Public, @@ -608,12 +629,13 @@ export class CSharpRenderer extends ConvenienceRenderer { if (attributes === undefined) { if ( // Descriptions should be preceded by an empty line - (!isFirstProperty && description !== undefined) || + !isFirstProperty && description !== undefined || // If the previous property has a description, leave an empty line previousDescription !== undefined ) { this.ensureBlankLine(); } + this.emitDescription(description); this.emitLine(property); } else if (this._csOptions.dense && attributes.length > 0) { @@ -624,6 +646,7 @@ export class CSharpRenderer extends ConvenienceRenderer { for (const attribute of attributes) { this.emitLine(attribute); } + this.emitLine(property); } @@ -633,11 +656,11 @@ export class CSharpRenderer extends ConvenienceRenderer { if (columns.length > 0) { this.emitTable(columns); } - } + }, ); } - private emitUnionDefinition(u: UnionType, unionName: Name): void { + private emitUnionDefinition (u: UnionType, unionName: Name): void { const nonNulls = removeNullFromUnion(u, true)[1]; this.emitType( this.descriptionForType(u), @@ -653,23 +676,23 @@ export class CSharpRenderer extends ConvenienceRenderer { this.ensureBlankLine(); const nullTests: Sourcelike[] = Array.from(nonNulls).map(t => [ this.nameForUnionMember(u, t), - " == null" + " == null", ]); this.ensureBlankLine(); this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { const csType = this.csType(t); this.emitExpressionMember( ["public static implicit operator ", unionName, "(", csType, " ", fieldName, ")"], - ["new ", unionName, " { ", fieldName, " = ", fieldName, " }"] + ["new ", unionName, " { ", fieldName, " = ", fieldName, " }"], ); }); if (u.findMember("null") === undefined) return; this.emitExpressionMember("public bool IsNull", arrayIntercalate(" && ", nullTests), true); - } + }, ); } - private emitEnumDefinition(e: EnumType, enumName: Name): void { + private emitEnumDefinition (e: EnumType, enumName: Name): void { const caseNames: Sourcelike[] = []; this.forEachEnumCase(e, "none", name => { if (caseNames.length > 0) caseNames.push(", "); @@ -679,7 +702,7 @@ export class CSharpRenderer extends ConvenienceRenderer { this.emitLine("public enum ", enumName, " { ", caseNames, " };"); } - protected emitExpressionMember(declare: Sourcelike, define: Sourcelike, isProperty = false): void { + protected emitExpressionMember (declare: Sourcelike, define: Sourcelike, isProperty = false): void { if (this._csOptions.version === 5) { this.emitLine(declare); this.emitBlock(() => { @@ -701,7 +724,7 @@ export class CSharpRenderer extends ConvenienceRenderer { condition: (t: T) => Sourcelike, withBlock: boolean, withReturn: boolean, - f: (t: T) => void + f: (t: T) => void, ): void { assert(!withReturn || withBlock, "Can only have return with block"); for (const t of types) { @@ -719,40 +742,40 @@ export class CSharpRenderer extends ConvenienceRenderer { } } - protected emitUsing(ns: Sourcelike): void { + protected emitUsing (ns: Sourcelike): void { this.emitLine("using ", ns, ";"); } - protected emitUsings(): void { + protected emitUsings (): void { for (const ns of ["System", "System.Collections.Generic"]) { this.emitUsing(ns); } } - protected emitRequiredHelpers(): void { + protected emitRequiredHelpers (): void { return; } - private emitTypesAndSupport(): void { + private emitTypesAndSupport (): void { this.forEachObject("leading-and-interposing", (c: ClassType, name: Name) => this.emitClassDefinition(c, name)); this.forEachEnum("leading-and-interposing", (e, name) => this.emitEnumDefinition(e, name)); this.forEachUnion("leading-and-interposing", (u, name) => this.emitUnionDefinition(u, name)); this.emitRequiredHelpers(); } - protected emitDefaultLeadingComments(): void { + protected emitDefaultLeadingComments (): void { return; } - protected emitDefaultFollowingComments(): void { + protected emitDefaultFollowingComments (): void { return; } - protected needNamespace(): boolean { + protected needNamespace (): boolean { return true; } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -781,13 +804,15 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { private readonly _enumExtensionsNames = new Map(); private readonly _needHelpers: boolean; + private readonly _needAttributes: boolean; + private readonly _needNamespaces: boolean; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext, _options); this._needHelpers = _options.features.helpers; @@ -795,7 +820,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this._needNamespaces = _options.features.namespaces; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { const forbidden = [ "Converter", "JsonConverter", @@ -807,47 +832,51 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { "MetadataPropertyHandling", "DateParseHandling", "FromJson", - "Required" + "Required", ]; if (this._options.dense) { forbidden.push("J", "R", "N"); } + if (this._options.baseclass !== undefined) { forbidden.push(this._options.baseclass); } + return super.forbiddenNamesForGlobalNamespace().concat(forbidden); } - protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (c: ClassType, className: Name): ForbiddenWordsInfo { const result = super.forbiddenForObjectProperties(c, className); result.names = result.names.concat(["ToJson", "FromJson", "Required"]); return result; } - protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { + protected makeNameForTransformation (xf: Transformation, typeName: Name | undefined): Name { if (typeName === undefined) { let xfer = xf.transformer; if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { xfer = xfer.consumer; } + return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); } + return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); } - protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames (t: Type, name: Name): DependencyName[] { if (!(t instanceof EnumType)) return []; const extensionsName = new DependencyName( namingFunction, name.order + 30, - lookup => `${lookup(name)}_extensions` + lookup => `${lookup(name)}_extensions`, ); this._enumExtensionsNames.set(name, extensionsName); return [extensionsName]; } - protected emitUsings(): void { + protected emitUsings (): void { // FIXME: We need System.Collections.Generic whenever we have maps or use List. if (!this._needAttributes && !this._needHelpers) return; @@ -863,14 +892,17 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.emitUsing([denseRequiredEnumName, " = Newtonsoft.Json.Required"]); this.emitUsing([denseNullValueHandlingEnumName, " = Newtonsoft.Json.NullValueHandling"]); } + if (this._options.baseclass === "EntityData") { this.emitUsing("Microsoft.Azure.Mobile.Server"); } } - protected baseclassForType(_t: Type): Sourcelike | undefined { + + protected baseclassForType (_t: Type): Sourcelike | undefined { return this._options.baseclass; } - protected emitDefaultLeadingComments(): void { + + protected emitDefaultLeadingComments (): void { if (!this._needHelpers) return; this.emitLine("// "); @@ -878,7 +910,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.emitLine( "// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do", this.topLevels.size === 1 ? "" : " one of these", - ":" + ":", ); this.emitLine("//"); this.emitLine("// using ", this._options.namespace, ";"); @@ -890,11 +922,12 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } else { rhs = [topLevelName, ".FromJson(jsonString)"]; } + this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); }); } - private converterForType(t: Type): Name | undefined { + private converterForType (t: Type): Name | undefined { let xf = transformationForType(t); if (xf === undefined && t instanceof UnionType) { @@ -912,11 +945,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return defined(this.nameForTransformation(t)); } - protected attributesForProperty( + protected attributesForProperty ( property: ClassProperty, _name: Name, _c: ClassType, - jsonName: string + jsonName: string, ): Sourcelike[] | undefined { if (!this._needAttributes) return undefined; @@ -931,7 +964,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const nullValueHandling = isOptional && !isNullable ? [", NullValueHandling = ", nullValueHandlingClass, ".Ignore"] : []; let required: Sourcelike; - if (!this._options.checkRequired || (isOptional && isNullable)) { + if (!this._options.checkRequired || isOptional && isNullable) { required = [nullValueHandling]; } else if (isOptional && !isNullable) { required = [", Required = ", requiredClass, ".DisallowNull", nullValueHandling]; @@ -940,7 +973,8 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } else { required = [", Required = ", requiredClass, ".Always", nullValueHandling]; } - attributes.push(["[", jsonProperty, '("', escapedName, '"', required, ")]"]); + + attributes.push(["[", jsonProperty, "(\"", escapedName, "\"", required, ")]"]); const converter = this.converterForType(property.type); if (converter !== undefined) { @@ -950,16 +984,16 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return attributes; } - protected blankLinesBetweenAttributes(): boolean { + protected blankLinesBetweenAttributes (): boolean { return this._needAttributes && !this._options.dense; } // The "this" type can't be `dynamic`, so we have to force it to `object`. - private topLevelResultType(t: Type): Sourcelike { + private topLevelResultType (t: Type): Sourcelike { return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); } - private emitFromJsonForTopLevel(t: Type, name: Name): void { + private emitFromJsonForTopLevel (t: Type, name: Name): void { if (t instanceof EnumType) return; let partial: string; @@ -972,38 +1006,39 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { partial = ""; typeKind = "class"; } + const csType = this.topLevelResultType(t); this.emitType(undefined, AccessModifier.Public, [partial, typeKind], name, this.baseclassForType(t), () => { // FIXME: Make FromJson a Named this.emitExpressionMember( ["public static ", csType, " FromJson(string json)"], - ["JsonConvert.DeserializeObject<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] + ["JsonConvert.DeserializeObject<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"], ); }); } - private emitDecoderSwitch(emitBody: () => void): void { + private emitDecoderSwitch (emitBody: () => void): void { this.emitLine("switch (reader.TokenType)"); this.emitBlock(emitBody); } - private emitTokenCase(tokenType: string): void { + private emitTokenCase (tokenType: string): void { this.emitLine("case JsonToken.", tokenType, ":"); } - private emitThrow(message: Sourcelike): void { + private emitThrow (message: Sourcelike): void { this.emitLine("throw new Exception(", message, ");"); } - private deserializeTypeCode(typeName: Sourcelike): Sourcelike { + private deserializeTypeCode (typeName: Sourcelike): Sourcelike { return ["serializer.Deserialize<", typeName, ">(reader)"]; } - private serializeValueCode(value: Sourcelike): Sourcelike { + private serializeValueCode (value: Sourcelike): Sourcelike { return ["serializer.Serialize(writer, ", value, ")"]; } - private emitSerializeClass(): void { + private emitSerializeClass (): void { // FIXME: Make Serialize a Named this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { // Sometimes multiple top-levels will resolve to the same type, so we have to take care @@ -1015,39 +1050,39 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { seenTypes.add(t); this.emitExpressionMember( ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], - ["JsonConvert.SerializeObject(self, ", this._options.namespace, ".Converter.Settings)"] + ["JsonConvert.SerializeObject(self, ", this._options.namespace, ".Converter.Settings)"], ); } }); }); } - private emitCanConvert(expr: Sourcelike): void { + private emitCanConvert (expr: Sourcelike): void { this.emitExpressionMember("public override bool CanConvert(Type t)", expr); } - private emitReadJson(emitBody: () => void): void { + private emitReadJson (emitBody: () => void): void { this.emitLine( - "public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)" + "public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)", ); this.emitBlock(emitBody); } - private emitWriteJson(variable: string, emitBody: () => void): void { + private emitWriteJson (variable: string, emitBody: () => void): void { this.emitLine( "public override void WriteJson(JsonWriter writer, object ", variable, - ", JsonSerializer serializer)" + ", JsonSerializer serializer)", ); this.emitBlock(emitBody); } - private converterObject(converterName: Name): Sourcelike { + private converterObject (converterName: Name): Sourcelike { // FIXME: Get a singleton return [converterName, ".Singleton"]; } - private emitConverterClass(): void { + private emitConverterClass (): void { // FIXME: Make Converter a Named const converterName: Sourcelike = ["Converter"]; this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { @@ -1063,25 +1098,27 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.emitLine(this.converterObject(converter), ","); } } + this.emitLine("new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }"); }); - this.emitLine(`},`); + this.emitLine("},"); }, true); }); } - private emitDecoderTransformerCase( + private emitDecoderTransformerCase ( tokenCases: string[], variableName: string, xfer: Transformer | undefined, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): void { if (xfer === undefined) return; for (const tokenCase of tokenCases) { this.emitTokenCase(tokenCase); } + this.indent(() => { const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); if (!allHandled) { @@ -1090,11 +1127,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { }); } - private emitConsume( + private emitConsume ( value: Sourcelike, consumer: Transformer | undefined, targetType: Type, - emitFinish: (variableName: Sourcelike) => void + emitFinish: (variableName: Sourcelike) => void, ): boolean { if (consumer === undefined) { emitFinish(value); @@ -1104,11 +1141,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } } - private emitDecodeTransformer( + private emitDecodeTransformer ( xfer: Transformer, targetType: Type, emitFinish: (value: Sourcelike) => void, - variableName = "value" + variableName = "value", ): boolean { if (xfer instanceof DecodingTransformer) { const source = xfer.sourceType; @@ -1123,18 +1160,20 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { typeSource, ")converter.ReadJson(reader, typeof(", typeSource, - "), null, serializer);" + "), null, serializer);", ); } else if (source.kind !== "null") { let output = targetType.kind === "double" ? targetType : source; this.emitLine("var ", variableName, " = ", this.deserializeTypeCode(this.csType(output)), ";"); } + return this.emitConsume(variableName, xfer.consumer, targetType, emitFinish); } else if (xfer instanceof ArrayDecodingTransformer) { // FIXME: Consume StartArray if (!(targetType instanceof ArrayType)) { return panic("Array decoding must produce an array type"); } + // FIXME: handle EOF this.emitLine("reader.Read();"); this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); @@ -1144,7 +1183,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { xfer.itemTransformer, xfer.itemTargetType, v => this.emitLine(variableName, ".Add(", v, ");"), - "arrayItem" + "arrayItem", ); // FIXME: handle EOF this.emitLine("reader.Read();"); @@ -1153,6 +1192,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { if (!this._options.useList) { result = [result, ".ToArray()"]; } + emitFinish(result); return true; } else if (xfer instanceof DecodingChoiceTransformer) { @@ -1167,19 +1207,20 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } }); } + this.emitDecoderTransformerCase( ["Integer"], "integerValue", xfer.integerTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( xfer.integerTransformer === undefined ? ["Integer", "Float"] : ["Float"], "doubleValue", xfer.doubleTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase(["Boolean"], "boolValue", xfer.boolTransformer, targetType, emitFinish); this.emitDecoderTransformerCase( @@ -1187,21 +1228,21 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { "stringValue", xfer.stringTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( ["StartObject"], "objectValue", xfer.objectTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( ["StartArray"], "arrayValue", xfer.arrayTransformer, targetType, - emitFinish + emitFinish, ); }); return false; @@ -1210,25 +1251,27 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } } - private stringCaseValue(t: Type, stringCase: string): Sourcelike { + private stringCaseValue (t: Type, stringCase: string): Sourcelike { if (t.kind === "string") { - return ['"', utf16StringEscape(stringCase), '"']; + return ["\"", utf16StringEscape(stringCase), "\""]; } else if (t instanceof EnumType) { return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; } + return panic(`Type ${t.kind} does not have string cases`); } - private emitTransformer( + private emitTransformer ( variable: Sourcelike, xfer: Transformer, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): boolean { - function directTargetType(continuation: Transformer | undefined): Type { + function directTargetType (continuation: Transformer | undefined): Type { if (continuation === undefined) { return targetType; } + return followTargetType(continuation.sourceType); } @@ -1241,7 +1284,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const matchXfer = caseXfer as StringMatchTransformer; const value = this.stringCaseValue( followTargetType(matchXfer.sourceType), - matchXfer.stringCase + matchXfer.stringCase, ); this.emitLine("case ", value, ":"); this.indent(() => { @@ -1249,7 +1292,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { variable, matchXfer.transformer, targetType, - emitFinish + emitFinish, ); if (!allDone) { this.emitLine("break;"); @@ -1285,9 +1328,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { member = [variable, ".", memberName]; test = [member, " != null"]; } + if (memberType.kind !== "null" && isValueType(memberType)) { member = [member, ".Value"]; } + this.emitLine("if (", test, ")"); this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); } else if (xfer instanceof StringMatchTransformer) { @@ -1302,6 +1347,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } else { this.emitLine(this.serializeValueCode(variable), ";"); } + emitFinish([]); return true; } else if (xfer instanceof ArrayEncodingTransformer) { @@ -1354,23 +1400,23 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { switch (xfer.sourceType.kind) { case "date-time": return this.emitConsume( - [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], + [variable, ".ToString(\"o\", System.Globalization.CultureInfo.InvariantCulture)"], xfer.consumer, targetType, - emitFinish + emitFinish, ); case "uuid": return this.emitConsume( - [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], + [variable, ".ToString(\"D\", System.Globalization.CultureInfo.InvariantCulture)"], xfer.consumer, targetType, - emitFinish + emitFinish, ); case "integer": case "uri": return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); case "bool": - this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); + this.emitLine("var boolString = ", variable, " ? \"true\" : \"false\";"); return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); default: return panic(`Stringifying ${xfer.sourceType.kind} not supported`); @@ -1386,9 +1432,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { if (min !== undefined) { conditions.push([variable, ".Length >= ", min.toString()]); } + if (max !== undefined) { conditions.push([variable, ".Length <= ", max.toString()]); } + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); return false; @@ -1400,9 +1448,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { if (min !== undefined) { conditions.push([variable, " >= ", min.toString()]); } + if (max !== undefined) { conditions.push([variable, " <= ", max.toString()]); } + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); return false; @@ -1410,6 +1460,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { if (!(targetType instanceof UnionType)) { return panic("Union instantiation transformer must produce a union type"); } + const maybeNullable = nullableFromUnion(targetType); if (maybeNullable !== null) { emitFinish(variable); @@ -1422,16 +1473,19 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const memberName = this.nameForUnionMember(targetType, xfer.sourceType); initializer = [" ", memberName, " = ", variable, " "]; } + emitFinish(["new ", unionName, " {", initializer, "}"]); } + return true; } else { return panic("Unknown transformer"); } + return false; } - private emitTransformation(converterName: Name, t: Type): void { + private emitTransformation (converterName: Name, t: Type): void { const xf = defined(transformationForType(t)); const reverse = xf.reverse; const targetType = xf.targetType; @@ -1443,6 +1497,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { if (haveNullable) { canConvertExpr = [canConvertExpr, " || t == typeof(", csType, "?)"]; } + this.emitCanConvert(canConvertExpr); this.ensureBlankLine(); this.emitReadJson(() => { @@ -1458,7 +1513,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const allHandled = this.emitDecodeTransformer(xfer, targetType, v => this.emitLine("return ", v, ";")); if (!allHandled) { - this.emitThrow(['"Cannot unmarshal type ', csType, '"']); + this.emitThrow(["\"Cannot unmarshal type ", csType, "\""]); } }); this.ensureBlankLine(); @@ -1471,12 +1526,13 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.emitLine("return;"); }); } + this.emitLine("var value = (", csType, ")untypedValue;"); const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;") + this.emitLine("return;"), ); if (!allHandled) { - this.emitThrow(['"Cannot marshal type ', csType, '"']); + this.emitThrow(["\"Cannot marshal type ", csType, "\""]); } }); this.ensureBlankLine(); @@ -1484,20 +1540,21 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { }); } - protected emitRequiredHelpers(): void { + protected emitRequiredHelpers (): void { if (this._needHelpers) { this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); this.ensureBlankLine(); this.emitSerializeClass(); } - if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { + + if (this._needHelpers || this._needAttributes && (this.haveNamedUnions || this.haveEnums)) { this.ensureBlankLine(); this.emitConverterClass(); this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); } } - protected needNamespace(): boolean { + protected needNamespace (): boolean { return this._needNamespaces; } } @@ -1508,13 +1565,15 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { private readonly _enumExtensionsNames = new Map(); private readonly _needHelpers: boolean; + private readonly _needAttributes: boolean; + private readonly _needNamespaces: boolean; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext, _options); this._needHelpers = _options.features.helpers; @@ -1522,7 +1581,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this._needNamespaces = _options.features.namespaces; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { const forbidden = [ "Converter", "JsonConverter", @@ -1535,47 +1594,51 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // "MetadataPropertyHandling", // "DateParseHandling", "FromJson", - "Required" + "Required", ]; if (this._options.dense) { forbidden.push("J", "R", "N"); } + if (this._options.baseclass !== undefined) { forbidden.push(this._options.baseclass); } + return super.forbiddenNamesForGlobalNamespace().concat(forbidden); } - protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (c: ClassType, className: Name): ForbiddenWordsInfo { const result = super.forbiddenForObjectProperties(c, className); result.names = result.names.concat(["ToJson", "FromJson", "Required"]); return result; } - protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { + protected makeNameForTransformation (xf: Transformation, typeName: Name | undefined): Name { if (typeName === undefined) { let xfer = xf.transformer; if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { xfer = xfer.consumer; } + return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); } + return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); } - protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames (t: Type, name: Name): DependencyName[] { if (!(t instanceof EnumType)) return []; const extensionsName = new DependencyName( namingFunction, name.order + 30, - lookup => `${lookup(name)}_extensions` + lookup => `${lookup(name)}_extensions`, ); this._enumExtensionsNames.set(name, extensionsName); return [extensionsName]; } - protected emitUsings(): void { + protected emitUsings (): void { // FIXME: We need System.Collections.Generic whenever we have maps or use List. if (!this._needAttributes && !this._needHelpers) return; @@ -1591,16 +1654,17 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // this.emitUsing([denseRequiredEnumName, " = Newtonsoft.Json.Required"]); this.emitUsing([denseNullValueHandlingEnumName, " = System.Text.Json.Serialization.JsonIgnoreCondition"]); } + if (this._options.baseclass === "EntityData") { this.emitUsing("Microsoft.Azure.Mobile.Server"); } } - protected baseclassForType(_t: Type): Sourcelike | undefined { + protected baseclassForType (_t: Type): Sourcelike | undefined { return this._options.baseclass; } - protected emitDefaultFollowingComments(): void { + protected emitDefaultFollowingComments (): void { if (!this._needHelpers) return; this.emitLine("#pragma warning restore CS8618"); @@ -1608,7 +1672,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitLine("#pragma warning restore CS8603"); } - protected emitDefaultLeadingComments(): void { + protected emitDefaultLeadingComments (): void { if (!this._needHelpers) return; this.emitLine("// "); @@ -1616,7 +1680,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitLine( "// To parse this JSON data, add NuGet 'System.Text.Json' then do", this.topLevels.size === 1 ? "" : " one of these", - ":" + ":", ); this.emitLine("//"); this.emitLine("// using ", this._options.namespace, ";"); @@ -1628,6 +1692,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } else { rhs = [topLevelName, ".FromJson(jsonString)"]; } + this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); }); @@ -1638,7 +1703,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitLine("#pragma warning disable CS8603"); } - private converterForType(t: Type): Name | undefined { + private converterForType (t: Type): Name | undefined { let xf = transformationForType(t); if (xf === undefined && t instanceof UnionType) { @@ -1656,11 +1721,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return defined(this.nameForTransformation(t)); } - protected attributesForProperty( + protected attributesForProperty ( property: ClassProperty, _name: Name, _c: ClassType, - jsonName: string + jsonName: string, ): Sourcelike[] | undefined { if (!this._needAttributes) return undefined; @@ -1689,7 +1754,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // required = [", Required = ", requiredClass, ".Always", nullValueHandling]; // } - attributes.push(["[", jsonPropertyName, '("', escapedName, '")]']); + attributes.push(["[", jsonPropertyName, "(\"", escapedName, "\")]"]); const converter = this.converterForType(property.type); if (converter !== undefined) { @@ -1699,16 +1764,16 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return attributes; } - protected blankLinesBetweenAttributes(): boolean { + protected blankLinesBetweenAttributes (): boolean { return this._needAttributes && !this._options.dense; } // The "this" type can't be `dynamic`, so we have to force it to `object`. - private topLevelResultType(t: Type): Sourcelike { + private topLevelResultType (t: Type): Sourcelike { return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); } - private emitFromJsonForTopLevel(t: Type, name: Name): void { + private emitFromJsonForTopLevel (t: Type, name: Name): void { if (t instanceof EnumType) return; let partial: string; @@ -1721,30 +1786,31 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { partial = ""; typeKind = "class"; } + const csType = this.topLevelResultType(t); this.emitType(undefined, AccessModifier.Public, [partial, typeKind], name, this.baseclassForType(t), () => { // FIXME: Make FromJson a Named this.emitExpressionMember( ["public static ", csType, " FromJson(string json)"], - ["JsonSerializer.Deserialize<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] + ["JsonSerializer.Deserialize<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"], ); }); } - private emitDecoderSwitch(emitBody: () => void): void { + private emitDecoderSwitch (emitBody: () => void): void { this.emitLine("switch (reader.TokenType)"); this.emitBlock(emitBody); } - private emitTokenCase(tokenType: string): void { + private emitTokenCase (tokenType: string): void { this.emitLine("case JsonTokenType.", tokenType, ":"); } - private emitThrow(message: Sourcelike): void { + private emitThrow (message: Sourcelike): void { this.emitLine("throw new Exception(", message, ");"); } - private deserializeTypeCode(typeName: Sourcelike): Sourcelike { + private deserializeTypeCode (typeName: Sourcelike): Sourcelike { switch (typeName) { case "bool": return ["reader.GetBoolean()"]; @@ -1761,12 +1827,12 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } } - private serializeValueCode(value: Sourcelike): Sourcelike { + private serializeValueCode (value: Sourcelike): Sourcelike { if (value !== "null") return ["JsonSerializer.Serialize(writer, ", value, ", options)"]; else return ["writer.WriteNullValue()"]; } - private emitSerializeClass(): void { + private emitSerializeClass (): void { // FIXME: Make Serialize a Named this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { // Sometimes multiple top-levels will resolve to the same type, so we have to take care @@ -1778,49 +1844,49 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { seenTypes.add(t); this.emitExpressionMember( ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], - ["JsonSerializer.Serialize(self, ", this._options.namespace, ".Converter.Settings)"] + ["JsonSerializer.Serialize(self, ", this._options.namespace, ".Converter.Settings)"], ); } }); }); } - private emitCanConvert(expr: Sourcelike): void { + private emitCanConvert (expr: Sourcelike): void { this.emitExpressionMember("public override bool CanConvert(Type t)", expr); } - private emitReadJson(emitBody: () => void, csType: Sourcelike): void { + private emitReadJson (emitBody: () => void, csType: Sourcelike): void { this.emitLine( "public override ", csType, - " Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)" + " Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)", ); this.emitBlock(emitBody); } - private emitWriteJson(variable: string, emitBody: () => void, csType: Sourcelike): void { + private emitWriteJson (variable: string, emitBody: () => void, csType: Sourcelike): void { this.emitLine( "public override void Write(Utf8JsonWriter writer, ", csType, " ", variable, - ", JsonSerializerOptions options)" + ", JsonSerializerOptions options)", ); this.emitBlock(emitBody); } - private converterObject(converterName: Name): Sourcelike { + private converterObject (converterName: Name): Sourcelike { // FIXME: Get a singleton return [converterName, ".Singleton"]; } - private emitConverterClass(): void { + private emitConverterClass (): void { // FIXME: Make Converter a Named const converterName: Sourcelike = ["Converter"]; this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { // Do not use .Web as defaults. That turns on caseInsensitive property names and will fail the keywords test. this.emitLine( - "public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)" + "public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)", ); this.emitBlock(() => { // this.emitLine("MetadataPropertyHandling = MetadataPropertyHandling.Ignore,"); @@ -1833,28 +1899,30 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitLine(this.converterObject(converter), ","); } } + this.emitLine("new DateOnlyConverter(),"); this.emitLine("new TimeOnlyConverter(),"); this.emitLine("IsoDateTimeOffsetConverter.Singleton"); // this.emitLine("new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }"); }); - this.emitLine(`},`); + this.emitLine("},"); }, true); }); } - private emitDecoderTransformerCase( + private emitDecoderTransformerCase ( tokenCases: string[], variableName: string, xfer: Transformer | undefined, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): void { if (xfer === undefined) return; for (const tokenCase of tokenCases) { this.emitTokenCase(tokenCase); } + this.indent(() => { const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); if (!allHandled) { @@ -1863,11 +1931,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { }); } - private emitConsume( + private emitConsume ( value: Sourcelike, consumer: Transformer | undefined, targetType: Type, - emitFinish: (variableName: Sourcelike) => void + emitFinish: (variableName: Sourcelike) => void, ): boolean { if (consumer === undefined) { emitFinish(value); @@ -1877,11 +1945,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } } - private emitDecodeTransformer( + private emitDecodeTransformer ( xfer: Transformer, targetType: Type, emitFinish: (value: Sourcelike) => void, - variableName = "value" + variableName = "value", ): boolean { if (xfer instanceof DecodingTransformer) { const source = xfer.sourceType; @@ -1896,18 +1964,20 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { typeSource, ")converter.ReadJson(reader, typeof(", typeSource, - "), null, serializer);" + "), null, serializer);", ); } else if (source.kind !== "null") { let output = targetType.kind === "double" ? targetType : source; this.emitLine("var ", variableName, " = ", this.deserializeTypeCode(this.csType(output)), ";"); } + return this.emitConsume(variableName, xfer.consumer, targetType, emitFinish); } else if (xfer instanceof ArrayDecodingTransformer) { // FIXME: Consume StartArray if (!(targetType instanceof ArrayType)) { return panic("Array decoding must produce an array type"); } + // FIXME: handle EOF this.emitLine("reader.Read();"); this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); @@ -1917,7 +1987,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { xfer.itemTransformer, xfer.itemTargetType, v => this.emitLine(variableName, ".Add(", v, ");"), - "arrayItem" + "arrayItem", ); // FIXME: handle EOF this.emitLine("reader.Read();"); @@ -1926,6 +1996,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { if (!this._options.useList) { result = [result, ".ToArray()"]; } + emitFinish(result); return true; } else if (xfer instanceof DecodingChoiceTransformer) { @@ -1940,12 +2011,13 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } }); } + this.emitDecoderTransformerCase( ["Number"], "integerValue", xfer.integerTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( ["Number"], @@ -1953,14 +2025,14 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { "doubleValue", xfer.doubleTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( ["True", "False"], "boolValue", xfer.boolTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( // ["String", "Date"], @@ -1968,21 +2040,21 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { "stringValue", xfer.stringTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( ["StartObject"], "objectValue", xfer.objectTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( ["StartArray"], "arrayValue", xfer.arrayTransformer, targetType, - emitFinish + emitFinish, ); }); return false; @@ -1991,25 +2063,27 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } } - private stringCaseValue(t: Type, stringCase: string): Sourcelike { + private stringCaseValue (t: Type, stringCase: string): Sourcelike { if (t.kind === "string") { - return ['"', utf16StringEscape(stringCase), '"']; + return ["\"", utf16StringEscape(stringCase), "\""]; } else if (t instanceof EnumType) { return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; } + return panic(`Type ${t.kind} does not have string cases`); } - private emitTransformer( + private emitTransformer ( variable: Sourcelike, xfer: Transformer, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): boolean { - function directTargetType(continuation: Transformer | undefined): Type { + function directTargetType (continuation: Transformer | undefined): Type { if (continuation === undefined) { return targetType; } + return followTargetType(continuation.sourceType); } @@ -2022,7 +2096,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { const matchXfer = caseXfer as StringMatchTransformer; const value = this.stringCaseValue( followTargetType(matchXfer.sourceType), - matchXfer.stringCase + matchXfer.stringCase, ); this.emitLine("case ", value, ":"); this.indent(() => { @@ -2030,7 +2104,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { variable, matchXfer.transformer, targetType, - emitFinish + emitFinish, ); if (!allDone) { this.emitLine("break;"); @@ -2066,9 +2140,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { member = [variable, ".", memberName]; test = [member, " != null"]; } + if (memberType.kind !== "null" && isValueType(memberType)) { member = [member, ".Value"]; } + this.emitLine("if (", test, ")"); this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); } else if (xfer instanceof StringMatchTransformer) { @@ -2083,6 +2159,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } else { this.emitLine(this.serializeValueCode(variable), ";"); } + emitFinish([]); return true; } else if (xfer instanceof ArrayEncodingTransformer) { @@ -2115,7 +2192,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitBlock(() => { // this.emitLine("var uri = new Uri(", variable, ");"); // The default value about:blank should never happen, but this way we avoid a null reference warning. - this.emitLine('var uri = new Uri("about:blank");'); + this.emitLine("var uri = new Uri(\"about:blank\");"); this.emitLine("if (!string.IsNullOrEmpty(stringValue))"); this.emitBlock(() => { this.emitLine("uri = new Uri(", variable, ");"); @@ -2141,23 +2218,23 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { switch (xfer.sourceType.kind) { case "date-time": return this.emitConsume( - [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], + [variable, ".ToString(\"o\", System.Globalization.CultureInfo.InvariantCulture)"], xfer.consumer, targetType, - emitFinish + emitFinish, ); case "uuid": return this.emitConsume( - [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], + [variable, ".ToString(\"D\", System.Globalization.CultureInfo.InvariantCulture)"], xfer.consumer, targetType, - emitFinish + emitFinish, ); case "integer": case "uri": return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); case "bool": - this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); + this.emitLine("var boolString = ", variable, " ? \"true\" : \"false\";"); return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); default: return panic(`Stringifying ${xfer.sourceType.kind} not supported`); @@ -2173,9 +2250,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { if (min !== undefined) { conditions.push([variable, ".Length >= ", min.toString()]); } + if (max !== undefined) { conditions.push([variable, ".Length <= ", max.toString()]); } + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); return false; @@ -2187,9 +2266,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { if (min !== undefined) { conditions.push([variable, " >= ", min.toString()]); } + if (max !== undefined) { conditions.push([variable, " <= ", max.toString()]); } + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); return false; @@ -2197,6 +2278,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { if (!(targetType instanceof UnionType)) { return panic("Union instantiation transformer must produce a union type"); } + const maybeNullable = nullableFromUnion(targetType); if (maybeNullable !== null) { emitFinish(variable); @@ -2209,16 +2291,19 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { const memberName = this.nameForUnionMember(targetType, xfer.sourceType); initializer = [" ", memberName, " = ", variable, " "]; } + emitFinish(["new ", unionName, " {", initializer, "}"]); } + return true; } else { return panic("Unknown transformer"); } + return false; } - private emitTransformation(converterName: Name, t: Type): void { + private emitTransformation (converterName: Name, t: Type): void { const xf = defined(transformationForType(t)); const reverse = xf.reverse; const targetType = xf.targetType; @@ -2252,10 +2337,10 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // } const allHandled = this.emitDecodeTransformer(xfer, targetType, v => - this.emitLine("return ", v, ";") + this.emitLine("return ", v, ";"), ); if (!allHandled) { - this.emitThrow(['"Cannot unmarshal type ', csType, '"']); + this.emitThrow(["\"Cannot unmarshal type ", csType, "\""]); } }, csType); this.ensureBlankLine(); @@ -2272,27 +2357,28 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // } const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;") + this.emitLine("return;"), ); if (!allHandled) { - this.emitThrow(['"Cannot marshal type ', csType, '"']); + this.emitThrow(["\"Cannot marshal type ", csType, "\""]); } }, - csType + csType, ); this.ensureBlankLine(); this.emitLine("public static readonly ", converterName, " Singleton = new ", converterName, "();"); - } + }, ); } - protected emitRequiredHelpers(): void { + protected emitRequiredHelpers (): void { if (this._needHelpers) { this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); this.ensureBlankLine(); this.emitSerializeClass(); } - if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { + + if (this._needHelpers || this._needAttributes && (this.haveNamedUnions || this.haveEnums)) { this.ensureBlankLine(); this.emitConverterClass(); this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); @@ -2409,7 +2495,7 @@ internal class IsoDateTimeOffsetConverter : JsonConverter } } - protected needNamespace(): boolean { + protected needNamespace (): boolean { return this._needNamespaces; } } diff --git a/packages/quicktype-core/src/language/Crystal.ts b/packages/quicktype-core/src/language/Crystal.ts index 3b469fe15..61fcd28c9 100644 --- a/packages/quicktype-core/src/language/Crystal.ts +++ b/packages/quicktype-core/src/language/Crystal.ts @@ -1,5 +1,6 @@ import { TargetLanguage } from "../TargetLanguage"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { legalizeCharacters, splitIntoWords, @@ -12,30 +13,32 @@ import { escapeNonPrintableMapper, isPrintable, isAscii, - isLetterOrUnderscore + isLetterOrUnderscore, } from "../support/Strings"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { UnionType, Type, ClassType, EnumType } from "../Type"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type UnionType, type Type, type ClassType, type EnumType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { Sourcelike, maybeAnnotated } from "../Source"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { Option } from "../RendererOptions"; -import { RenderContext } from "../Renderer"; +import { type Option } from "../RendererOptions"; +import { type RenderContext } from "../Renderer"; export class CrystalTargetLanguage extends TargetLanguage { - protected makeRenderer(renderContext: RenderContext): CrystalRenderer { + protected makeRenderer (renderContext: RenderContext): CrystalRenderer { return new CrystalRenderer(this, renderContext); } - constructor() { + constructor () { super("Crystal", ["crystal", "cr", "crystallang"], "cr"); } - protected get defaultIndentation(): string { + protected get defaultIndentation (): string { return " "; } - protected getOptions(): Option[] { + protected getOptions (): Array> { return []; } } @@ -176,26 +179,28 @@ const keywords = [ "when", "while", "with", - "yield" + "yield", ]; -function isAsciiLetterOrUnderscoreOrDigit(codePoint: number): boolean { +function isAsciiLetterOrUnderscoreOrDigit (codePoint: number): boolean { if (!isAscii(codePoint)) { return false; } + return isLetterOrUnderscoreOrDigit(codePoint); } -function isAsciiLetterOrUnderscore(codePoint: number): boolean { +function isAsciiLetterOrUnderscore (codePoint: number): boolean { if (!isAscii(codePoint)) { return false; } + return isLetterOrUnderscore(codePoint); } const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); -function crystalStyle(original: string, isSnakeCase: boolean): string { +function crystalStyle (original: string, isSnakeCase: boolean): string { const words = splitIntoWords(original); const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; @@ -208,7 +213,7 @@ function crystalStyle(original: string, isSnakeCase: boolean): string { wordStyle, wordStyle, isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore + isAsciiLetterOrUnderscore, ); return combined === "_" ? "_underscore" : combined; @@ -217,7 +222,7 @@ function crystalStyle(original: string, isSnakeCase: boolean): string { const snakeNamingFunction = funPrefixNamer("default", (original: string) => crystalStyle(original, true)); const camelNamingFunction = funPrefixNamer("camel", (original: string) => crystalStyle(original, false)); -function standardUnicodeCrystalEscape(codePoint: number): string { +function standardUnicodeCrystalEscape (codePoint: number): string { if (codePoint <= 0xffff) { return "\\u{" + intToHex(codePoint, 4) + "}"; } else { @@ -228,56 +233,56 @@ function standardUnicodeCrystalEscape(codePoint: number): string { const crystalStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeCrystalEscape)); export class CrystalRenderer extends ConvenienceRenderer { - constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) { + constructor (targetLanguage: TargetLanguage, renderContext: RenderContext) { super(targetLanguage, renderContext); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return camelNamingFunction; } - protected namerForObjectProperty(): Namer | null { + protected namerForObjectProperty (): Namer | null { return snakeNamingFunction; } - protected makeUnionMemberNamer(): Namer | null { + protected makeUnionMemberNamer (): Namer | null { return camelNamingFunction; } - protected makeEnumCaseNamer(): Namer | null { + protected makeEnumCaseNamer (): Namer | null { return camelNamingFunction; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected get commentLineStart(): string { + protected get commentLineStart (): string { return "# "; } - private nullableCrystalType(t: Type, withIssues: boolean): Sourcelike { + private nullableCrystalType (t: Type, withIssues: boolean): Sourcelike { return [this.crystalType(t, withIssues), "?"]; } - protected isImplicitCycleBreaker(t: Type): boolean { + protected isImplicitCycleBreaker (t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } - private crystalType(t: Type, withIssues = false): Sourcelike { + private crystalType (t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "JSON::Any?"), @@ -300,23 +305,23 @@ export class CrystalRenderer extends ConvenienceRenderer { const name = this.nameForNamedType(unionType); return hasNull !== null ? ([name, "?"] as Sourcelike) : name; - } + }, ); } - private breakCycle(t: Type, withIssues: boolean): Sourcelike { + private breakCycle (t: Type, withIssues: boolean): Sourcelike { return this.crystalType(t, withIssues); } - private emitRenameAttribute(propName: Name, jsonName: string): void { + private emitRenameAttribute (propName: Name, jsonName: string): void { const escapedName = crystalStringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; if (namesDiffer) { - this.emitLine('@[JSON::Field(key: "', escapedName, '")]'); + this.emitLine("@[JSON::Field(key: \"", escapedName, "\")]"); } } - protected emitStructDefinition(c: ClassType, className: Name): void { + protected emitStructDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); const structBody = () => @@ -330,7 +335,7 @@ export class CrystalRenderer extends ConvenienceRenderer { this.emitBlock(["class ", className], structBody); } - protected emitBlock(line: Sourcelike, f: () => void): void { + protected emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line); this.indent(() => { this.emitLine("include JSON::Serializable"); @@ -340,13 +345,13 @@ export class CrystalRenderer extends ConvenienceRenderer { this.emitLine("end"); } - protected emitEnum(line: Sourcelike, f: () => void): void { + protected emitEnum (line: Sourcelike, f: () => void): void { this.emitLine(line); this.indent(f); this.emitLine("end"); } - protected emitUnion(u: UnionType, unionName: Name): void { + protected emitUnion (u: UnionType, unionName: Name): void { const isMaybeWithSingleType = nullableFromUnion(u); if (isMaybeWithSingleType !== null) { @@ -367,30 +372,30 @@ export class CrystalRenderer extends ConvenienceRenderer { "alias ", unionName, " = ", - types.map(r => r.map(sl => this.sourcelikeToString(sl))).join(" | ") + types.map(r => r.map(sl => this.sourcelikeToString(sl))).join(" | "), ]); } - protected emitTopLevelAlias(t: Type, name: Name): void { + protected emitTopLevelAlias (t: Type, name: Name): void { this.emitLine("alias ", name, " = ", this.crystalType(t)); } - protected emitLeadingComments(): void { + protected emitLeadingComments (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); return; } } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.emitLeadingComments(); this.ensureBlankLine(); - this.emitLine('require "json"'); + this.emitLine("require \"json\""); this.forEachTopLevel( "leading", (t, name) => this.emitTopLevelAlias(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); this.forEachObject("leading-and-interposing", (c: ClassType, name: Name) => this.emitStructDefinition(c, name)); diff --git a/packages/quicktype-core/src/language/Dart.ts b/packages/quicktype-core/src/language/Dart.ts index 6dc40ead6..308d8091b 100644 --- a/packages/quicktype-core/src/language/Dart.ts +++ b/packages/quicktype-core/src/language/Dart.ts @@ -1,14 +1,17 @@ import { - ClassProperty, - ClassType, + type ClassProperty, + type ClassType, + type PrimitiveStringTypeKind, + type TransformedStringTypeKind, + type Type, + type UnionType, +} from "../Type"; +import { EnumType, - PrimitiveStringTypeKind, - TransformedStringTypeKind, - Type, - UnionType } from "../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; -import { maybeAnnotated, modifySource, Sourcelike } from "../Source"; +import { type Sourcelike } from "../Source"; +import { maybeAnnotated, modifySource } from "../Source"; import { allLowerWordStyle, allUpperWordStyle, @@ -24,18 +27,21 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../support/Strings"; -import { StringTypeMapping } from "../TypeBuilder"; +import { type StringTypeMapping } from "../TypeBuilder"; -import { DependencyName, funPrefixNamer, Name, Namer } from "../Naming"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer } from "../Naming"; +import { DependencyName, funPrefixNamer } from "../Naming"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { TargetLanguage } from "../TargetLanguage"; -import { BooleanOption, getOptionValues, Option, OptionValues, StringOption } from "../RendererOptions"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { BooleanOption, getOptionValues, StringOption } from "../RendererOptions"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { defined } from "../support/Support"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; export const dartOptions = { nullSafety: new BooleanOption("null-safety", "Null Safety", true), @@ -49,24 +55,24 @@ export const dartOptions = { "use-freezed", "Generate class definitions with @freezed compatibility", false, - "secondary" + "secondary", ), useHive: new BooleanOption("use-hive", "Generate annotations for Hive type adapters", false, "secondary"), useJsonAnnotation: new BooleanOption( "use-json-annotation", "Generate annotations for json_serializable", false, - "secondary" + "secondary", ), - partName: new StringOption("part-name", "Use this name in `part` directive", "NAME", "", "secondary") + partName: new StringOption("part-name", "Use this name in `part` directive", "NAME", "", "secondary"), }; export class DartTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Dart", ["dart"], "dart"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ dartOptions.nullSafety, dartOptions.justTypes, @@ -78,22 +84,22 @@ export class DartTargetLanguage extends TargetLanguage { dartOptions.useFreezed, dartOptions.useHive, dartOptions.useJsonAnnotation, - dartOptions.partName + dartOptions.partName, ]; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date"); mapping.set("date-time", "date-time"); return mapping; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): DartRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): DartRenderer { const options = getOptionValues(dartOptions, untypedOptionValues); return new DartRenderer(this, renderContext, options); } @@ -168,7 +174,7 @@ const keywords = [ "fromJson", "toJson", "fromMap", - "toMap" + "toMap", ]; const typeNamingFunction = funPrefixNamer("types", n => dartNameStyle(true, false, n)); @@ -177,16 +183,16 @@ const enumCaseNamingFunction = funPrefixNamer("enum-cases", n => dartNameStyle(t // Escape the dollar sign, which is used in string interpolation const stringEscape = utf16ConcatMap( - escapeNonPrintableMapper(cp => isPrintable(cp) && cp !== 0x24, standardUnicodeHexEscape) + escapeNonPrintableMapper(cp => isPrintable(cp) && cp !== 0x24, standardUnicodeHexEscape), ); -function isStartCharacter(codePoint: number): boolean { +function isStartCharacter (codePoint: number): boolean { if (codePoint === 0x5f) return false; // underscore return isAscii(codePoint) && isLetter(codePoint); } -function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); +function isPartCharacter (codePoint: number): boolean { + return isStartCharacter(codePoint) || isAscii(codePoint) && isDigit(codePoint); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); @@ -195,13 +201,13 @@ const legalizeName = utf16LegalizeCharacters(isPartCharacter); // we have to use namers to produce the getter and setter names - we can't // just capitalize and concatenate. // https://stackoverflow.com/questions/8277355/naming-convention-for-upper-case-abbreviations -function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, original: string): string { +function dartNameStyle (startWithUpper: boolean, upperUnderscore: boolean, original: string): string { const words = splitIntoWords(original); const firstWordStyle = upperUnderscore ? allUpperWordStyle : startWithUpper - ? firstUpperWordStyle - : allLowerWordStyle; + ? firstUpperWordStyle + : allLowerWordStyle; const restWordStyle = upperUnderscore ? allUpperWordStyle : firstUpperWordStyle; return combineWords( words, @@ -211,121 +217,126 @@ function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, origin firstWordStyle, restWordStyle, upperUnderscore ? "_" : "", - isStartCharacter + isStartCharacter, ); } -type TopLevelDependents = { - encoder: Name; +interface TopLevelDependents { decoder: Name; -}; + encoder: Name; +} export class DartRenderer extends ConvenienceRenderer { private readonly _gettersAndSettersForPropertyName = new Map(); + private _needEnumValues = false; + private classCounter = 0; + private classPropertyCounter = 0; + private readonly _topLevelDependents = new Map(); + private readonly _enumValues = new Map(); - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return typeNamingFunction; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return propertyNamingFunction; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return propertyNamingFunction; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return enumCaseNamingFunction; } - protected unionNeedsName(u: UnionType): boolean { + protected unionNeedsName (u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { // If the top-level type doesn't contain any classes or unions // we have to define a class just for the `FromJson` method, in // emitFromJsonForTopLevel. return directlyReachableSingleNamedType(type); } - protected get toJson(): string { + protected get toJson (): string { return `to${this._options.methodNamesWithMap ? "Map" : "Json"}`; } - protected get fromJson(): string { + protected get fromJson (): string { return `from${this._options.methodNamesWithMap ? "Map" : "Json"}`; } - protected makeTopLevelDependencyNames(_t: Type, name: Name): DependencyName[] { + protected makeTopLevelDependencyNames (_t: Type, name: Name): DependencyName[] { const encoder = new DependencyName( propertyNamingFunction, name.order, - lookup => `${lookup(name)}_${this.toJson}` + lookup => `${lookup(name)}_${this.toJson}`, ); const decoder = new DependencyName( propertyNamingFunction, name.order, - lookup => `${lookup(name)}_${this.fromJson}` + lookup => `${lookup(name)}_${this.fromJson}`, ); this._topLevelDependents.set(name, { encoder, decoder }); return [encoder, decoder]; } - protected makeNamesForPropertyGetterAndSetter( + protected makeNamesForPropertyGetterAndSetter ( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name + name: Name, ): [Name, Name] { const getterName = new DependencyName(propertyNamingFunction, name.order, lookup => `get_${lookup(name)}`); const setterName = new DependencyName(propertyNamingFunction, name.order, lookup => `set_${lookup(name)}`); return [getterName, setterName]; } - protected makePropertyDependencyNames( + protected makePropertyDependencyNames ( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return getterAndSetterNames; } - protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames (t: Type, name: Name): DependencyName[] { if (!(t instanceof EnumType)) return []; const enumValue = new DependencyName(propertyNamingFunction, name.order, lookup => `${lookup(name)}_values`); this._enumValues.set(t, enumValue); return [enumValue]; } - protected emitFileHeader(): void { + protected emitFileHeader (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } @@ -345,12 +356,15 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.requiredProperties) { this.emitLine("import 'package:meta/meta.dart';"); } + if (this._options.useFreezed) { this.emitLine("import 'package:freezed_annotation/freezed_annotation.dart';"); } + if (this._options.useHive) { this.emitLine("import 'package:hive/hive.dart';"); } + if (this._options.useJsonAnnotation && !this._options.useFreezed) { // The freezed annotatation import already provides the import for json_annotation this.emitLine("import 'package:json_annotation/json_annotation.dart';"); @@ -363,31 +377,32 @@ export class DartRenderer extends ConvenienceRenderer { // FIXME: This should use a `Name`, not `modifySource` const name = modifySource( snakeCase, - optionNameIsEmpty ? [...this.topLevels.keys()][0] : this._options.partName + optionNameIsEmpty ? [...this.topLevels.keys()][0] : this._options.partName, ); if (this._options.useFreezed) { this.emitLine("part '", name, ".freezed.dart';"); } + if (!this._options.justTypes) { this.emitLine("part '", name, ".g.dart';"); } } } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: "///", beforeComment: "" }); } - protected emitBlock(line: Sourcelike, f: () => void): void { + protected emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected dartType(t: Type, withIssues = false, forceNullable = false): Sourcelike { + protected dartType (t: Type, withIssues = false, forceNullable = false): Sourcelike { const nullable = - forceNullable || (this._options.nullSafety && t.isNullable && !this._options.requiredProperties); - const withNullable = (s: Sourcelike): Sourcelike => (nullable ? [s, "?"] : s); + forceNullable || this._options.nullSafety && t.isNullable && !this._options.requiredProperties; + const withNullable = (s: Sourcelike): Sourcelike => nullable ? [s, "?"] : s; return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "dynamic"), @@ -405,6 +420,7 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return "dynamic"; } + return withNullable(this.dartType(maybeNullable, withIssues)); }, transformedStringType => { @@ -415,25 +431,27 @@ export class DartRenderer extends ConvenienceRenderer { default: return withNullable("String"); } - } + }, ); } - protected mapList(isNullable: boolean, itemType: Sourcelike, list: Sourcelike, mapper: Sourcelike): Sourcelike { + protected mapList (isNullable: boolean, itemType: Sourcelike, list: Sourcelike, mapper: Sourcelike): Sourcelike { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return [list, " == null ? [] : ", "List<", itemType, ">.from(", list, "!.map((x) => ", mapper, "))"]; } + return ["List<", itemType, ">.from(", list, ".map((x) => ", mapper, "))"]; } - protected mapMap(isNullable: boolean, valueType: Sourcelike, map: Sourcelike, valueMapper: Sourcelike): Sourcelike { + protected mapMap (isNullable: boolean, valueType: Sourcelike, map: Sourcelike, valueMapper: Sourcelike): Sourcelike { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return ["Map.from(", map, "!).map((k, v) => MapEntry(k, ", valueMapper, "))"]; } + return ["Map.from(", map, ").map((k, v) => MapEntry(k, ", valueMapper, "))"]; } - protected mapClass(isNullable: boolean, classType: ClassType, dynamic: Sourcelike) { + protected mapClass (isNullable: boolean, classType: ClassType, dynamic: Sourcelike) { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return [ dynamic, @@ -443,16 +461,17 @@ export class DartRenderer extends ConvenienceRenderer { this.fromJson, "(", dynamic, - ")" + ")", ]; } + return [this.nameForNamedType(classType), ".", this.fromJson, "(", dynamic, ")"]; } - //If the first time is the unionType type, after nullableFromUnion conversion, - //the isNullable property will become false, which is obviously wrong, - //so add isNullable property - protected fromDynamicExpression(isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { + // If the first time is the unionType type, after nullableFromUnion conversion, + // the isNullable property will become false, which is obviously wrong, + // so add isNullable property + protected fromDynamicExpression (isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, _anyType => dynamic, @@ -466,7 +485,7 @@ export class DartRenderer extends ConvenienceRenderer { isNullable || arrayType.isNullable, this.dartType(arrayType.items), dynamic, - this.fromDynamicExpression(arrayType.items.isNullable, arrayType.items, "x") + this.fromDynamicExpression(arrayType.items.isNullable, arrayType.items, "x"), ), classType => this.mapClass(isNullable || classType.isNullable, classType, dynamic), mapType => @@ -474,14 +493,14 @@ export class DartRenderer extends ConvenienceRenderer { mapType.isNullable || isNullable, this.dartType(mapType.values), dynamic, - this.fromDynamicExpression(mapType.values.isNullable, mapType.values, "v") + this.fromDynamicExpression(mapType.values.isNullable, mapType.values, "v"), ), enumType => { return [ defined(this._enumValues.get(enumType)), ".map[", dynamic, - this._options.nullSafety ? "]!" : "]" + this._options.nullSafety ? "]!" : "]", ]; }, unionType => { @@ -489,6 +508,7 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return dynamic; } + return this.fromDynamicExpression(unionType.isNullable, maybeNullable, dynamic); }, transformedStringType => { @@ -502,18 +522,19 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, " == null ? null : ", "DateTime.parse(", dynamic, ")"]; } + return ["DateTime.parse(", dynamic, ")"]; default: return dynamic; } - } + }, ); } - //If the first time is the unionType type, after nullableFromUnion conversion, - //the isNullable property will become false, which is obviously wrong, - //so add isNullable property - protected toDynamicExpression(isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { + // If the first time is the unionType type, after nullableFromUnion conversion, + // the isNullable property will become false, which is obviously wrong, + // so add isNullable property + protected toDynamicExpression (isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, _anyType => dynamic, @@ -527,7 +548,7 @@ export class DartRenderer extends ConvenienceRenderer { arrayType.isNullable || isNullable, "dynamic", dynamic, - this.toDynamicExpression(arrayType.items.isNullable, arrayType.items, "x") + this.toDynamicExpression(arrayType.items.isNullable, arrayType.items, "x"), ), _classType => { if ( @@ -537,6 +558,7 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, "?.", this.toJson, "()"]; } + return [dynamic, ".", this.toJson, "()"]; }, mapType => @@ -544,7 +566,7 @@ export class DartRenderer extends ConvenienceRenderer { mapType.isNullable || isNullable, "dynamic", dynamic, - this.toDynamicExpression(mapType.values.isNullable, mapType.values, "v") + this.toDynamicExpression(mapType.values.isNullable, mapType.values, "v"), ), enumType => { return [defined(this._enumValues.get(enumType)), ".reverse[", dynamic, "]"]; @@ -554,6 +576,7 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return dynamic; } + return this.toDynamicExpression(unionType.isNullable, maybeNullable, dynamic); }, transformedStringType => { @@ -566,6 +589,7 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, "?.toIso8601String()"]; } + return [dynamic, ".toIso8601String()"]; case "date": if ( @@ -574,44 +598,45 @@ export class DartRenderer extends ConvenienceRenderer { (transformedStringType.isNullable || isNullable) ) { return [ - '"${', + "\"${", dynamic, "!.year.toString().padLeft(4, '0')", "}-${", dynamic, "!.month.toString().padLeft(2, '0')}-${", dynamic, - "!.day.toString().padLeft(2, '0')}\"" + "!.day.toString().padLeft(2, '0')}\"", ]; } + return [ - '"${', + "\"${", dynamic, ".year.toString().padLeft(4, '0')", "}-${", dynamic, ".month.toString().padLeft(2, '0')}-${", dynamic, - ".day.toString().padLeft(2, '0')}\"" + ".day.toString().padLeft(2, '0')}\"", ]; default: return dynamic; } - } + }, ); } - private _emitEmptyConstructor(className: Name): void { + private _emitEmptyConstructor (className: Name): void { this.emitLine(className, "();"); } - private _emitConstructor(c: ClassType, className: Name): void { + private _emitConstructor (c: ClassType, className: Name): void { this.emitLine(className, "({"); this.indent(() => { this.forEachClassProperty(c, "none", (name, _, prop) => { const required = this._options.requiredProperties || - (this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional)); + this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional); this.emitLine(required ? "required " : "", "this.", name, ","); }); }); @@ -619,7 +644,7 @@ export class DartRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - private _emitVariables(c: ClassType): void { + private _emitVariables (c: ClassType): void { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const description = this.descriptionForClassProperty(c, jsonName); if (description !== undefined) { @@ -640,7 +665,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - private _emitCopyConstructor(c: ClassType, className: Name): void { + private _emitCopyConstructor (c: ClassType, className: Name): void { this.ensureBlankLine(); this.emitLine(className, " copyWith({"); this.indent(() => { @@ -660,7 +685,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - private _emitStringJsonEncoderDecoder(className: Name): void { + private _emitStringJsonEncoderDecoder (className: Name): void { this.ensureBlankLine(); this.emitLine( "factory ", @@ -671,7 +696,7 @@ export class DartRenderer extends ConvenienceRenderer { className, ".", this.fromJson, - "(json.decode(str));" + "(json.decode(str));", ); this.ensureBlankLine(); @@ -680,11 +705,11 @@ export class DartRenderer extends ConvenienceRenderer { this._options.methodNamesWithMap ? "toJson() => " : "toRawJson() => ", "json.encode(", this.toJson, - "());" + "());", ); } - private _emitMapEncoderDecoder(c: ClassType, className: Name): void { + private _emitMapEncoderDecoder (c: ClassType, className: Name): void { this.ensureBlankLine(); this.emitLine("factory ", className, ".", this.fromJson, "(Map json) => ", className, "("); this.indent(() => { @@ -695,11 +720,11 @@ export class DartRenderer extends ConvenienceRenderer { this.fromDynamicExpression( property.type.isNullable, property.type, - 'json["', + "json[\"", stringEscape(jsonName), - '"]' + "\"]", ), - "," + ",", ); }); }); @@ -711,27 +736,29 @@ export class DartRenderer extends ConvenienceRenderer { this.indent(() => { this.forEachClassProperty(c, "none", (name, jsonName, property) => { this.emitLine( - '"', + "\"", stringEscape(jsonName), - '": ', + "\": ", this.toDynamicExpression(property.type.isNullable, property.type, name), - "," + ",", ); }); }); this.emitLine("};"); } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); if (this._options.useHive) { this.classCounter++; this.emitLine(`@HiveType(typeId: ${this.classCounter})`); this.classPropertyCounter = 0; } + if (this._options.useJsonAnnotation) { - this.emitLine(`@JsonSerializable()`); + this.emitLine("@JsonSerializable()"); } + this.emitBlock(["class ", className], () => { if (c.getProperties().size === 0) { this._emitEmptyConstructor(className); @@ -754,7 +781,7 @@ export class DartRenderer extends ConvenienceRenderer { ".fromJson(Map json) => ", "_$", className, - "FromJson(json);" + "FromJson(json);", ); this.ensureBlankLine(); @@ -763,7 +790,7 @@ export class DartRenderer extends ConvenienceRenderer { "Map toJson() => ", "_$", className, - "ToJson(this);" + "ToJson(this);", ); } else { if (this._options.justTypes) return; @@ -777,7 +804,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - protected emitFreezedClassDefinition(c: ClassType, className: Name): void { + protected emitFreezedClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("@freezed"); @@ -795,11 +822,12 @@ export class DartRenderer extends ConvenienceRenderer { const required = this._options.requiredProperties || - (this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional)); + this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional); if (this._options.useJsonAnnotation) { this.classPropertyCounter++; this.emitLine(`@JsonKey(name: "${jsonName}")`); } + this.emitLine(required ? "required " : "", this.dartType(prop.type, true), " ", name, ","); }); }); @@ -816,20 +844,21 @@ export class DartRenderer extends ConvenienceRenderer { ".fromJson(Map json) => ", "_$", className, - "FromJson(json);" + "FromJson(json);", ); }); } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine("enum ", enumName, " {"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName, pos) => { const comma = pos === "first" || pos === "middle" ? "," : []; if (this._options.useJsonAnnotation) { - this.emitLine('@JsonValue("', stringEscape(jsonName), '")'); + this.emitLine("@JsonValue(\"", stringEscape(jsonName), "\")"); } + this.emitLine(name, comma); }); }); @@ -842,7 +871,7 @@ export class DartRenderer extends ConvenienceRenderer { this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName, pos) => { const comma = pos === "first" || pos === "middle" ? "," : []; - this.emitLine('"', stringEscape(jsonName), '": ', enumName, ".", name, comma); + this.emitLine("\"", stringEscape(jsonName), "\": ", enumName, ".", name, comma); }); }); this.emitLine("});"); @@ -850,7 +879,7 @@ export class DartRenderer extends ConvenienceRenderer { this._needEnumValues = true; } - protected emitEnumValues(): void { + protected emitEnumValues (): void { this.ensureBlankLine(); this.emitMultiline(`class EnumValues { Map map; @@ -865,7 +894,7 @@ export class DartRenderer extends ConvenienceRenderer { }`); } - private _emitTopLvlEncoderDecoder(): void { + private _emitTopLvlEncoderDecoder (): void { this.forEachTopLevel("leading-and-interposing", (t, name) => { const { encoder, decoder } = defined(this._topLevelDependents.get(name)); @@ -875,7 +904,7 @@ export class DartRenderer extends ConvenienceRenderer { decoder, "(String str) => ", this.fromDynamicExpression(t.isNullable, t, "json.decode(str)"), - ";" + ";", ); this.ensureBlankLine(); @@ -887,7 +916,7 @@ export class DartRenderer extends ConvenienceRenderer { this.dartType(t), " data) => json.encode(", this.toDynamicExpression(t.isNullable, t, "data"), - ");" + ");", ); // this.emitBlock(["String ", encoder, "(", this.dartType(t), " data)"], () => { @@ -896,7 +925,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.emitFileHeader(); if (!this._options.justTypes && !this._options.codersInClass) { @@ -910,7 +939,7 @@ export class DartRenderer extends ConvenienceRenderer { (e, n) => this.emitEnumDefinition(e, n), (_e, _n) => { // We don't support this yet. - } + }, ); if (this._needEnumValues) { diff --git a/packages/quicktype-core/src/language/Elm.ts b/packages/quicktype-core/src/language/Elm.ts index bab36c541..01fa4f807 100644 --- a/packages/quicktype-core/src/language/Elm.ts +++ b/packages/quicktype-core/src/language/Elm.ts @@ -1,11 +1,15 @@ import { mapContains, arrayIntercalate } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { EnumOption, StringOption, BooleanOption, Option, getOptionValues, OptionValues } from "../RendererOptions"; -import { Type, ClassType, UnionType, EnumType, ClassProperty } from "../Type"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { EnumOption, StringOption, BooleanOption, getOptionValues } from "../RendererOptions"; +import { type Type, type ClassType, type EnumType, type ClassProperty } from "../Type"; +import { UnionType } from "../Type"; import { matchType, nullableFromUnion } from "../TypeUtils"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { Namer, Name, DependencyName, funPrefixNamer } from "../Naming"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Namer, type Name} from "../Naming"; +import { DependencyName, funPrefixNamer } from "../Naming"; import { legalizeCharacters, isLetterOrUnderscoreOrDigit, @@ -17,41 +21,42 @@ import { combineWords, firstUpperWordStyle, allLowerWordStyle, - allUpperWordStyle + allUpperWordStyle, } from "../support/Strings"; import { defined } from "../support/Support"; -import { Sourcelike, annotated, MultiWord, singleWord, multiWord, parenIfNeeded } from "../Source"; +import { type Sourcelike, type MultiWord} from "../Source"; +import { annotated, singleWord, multiWord, parenIfNeeded } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; export const elmOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), useList: new EnumOption("array-type", "Use Array or List", [ ["array", false], - ["list", true] + ["list", true], ]), // FIXME: Do this via a configurable named eventually. - moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") + moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType"), }; export class ElmTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Elm", ["elm"], "elm"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [elmOptions.justTypes, elmOptions.moduleName, elmOptions.useList]; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): ElmRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): ElmRenderer { return new ElmRenderer(this, renderContext, getOptionValues(elmOptions, untypedOptionValues)); } } @@ -94,12 +99,12 @@ const forbiddenNames = [ "True", "False", "String", - "Float" + "Float", ]; const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); -function elmNameStyle(original: string, upper: boolean): string { +function elmNameStyle (original: string, upper: boolean): string { const words = splitIntoWords(original); return combineWords( words, @@ -109,125 +114,131 @@ function elmNameStyle(original: string, upper: boolean): string { upper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } const upperNamingFunction = funPrefixNamer("upper", n => elmNameStyle(n, true)); const lowerNamingFunction = funPrefixNamer("lower", n => elmNameStyle(n, false)); -type RequiredOrOptional = { - reqOrOpt: string; +interface RequiredOrOptional { fallback: string; -}; + reqOrOpt: string; +} -function requiredOrOptional(p: ClassProperty): RequiredOrOptional { - function optional(fallback: string): RequiredOrOptional { +function requiredOrOptional (p: ClassProperty): RequiredOrOptional { + function optional (fallback: string): RequiredOrOptional { return { reqOrOpt: "Jpipe.optional", fallback }; } + const t = p.type; - if (p.isOptional || (t instanceof UnionType && nullableFromUnion(t) !== null)) { + if (p.isOptional || t instanceof UnionType && nullableFromUnion(t) !== null) { return optional(" Nothing"); } + if (t.kind === "null") { return optional(" ()"); } + return { reqOrOpt: "Jpipe.required", fallback: "" }; } -type TopLevelDependent = { - encoder: Name; +interface TopLevelDependent { decoder?: Name; -}; - -type NamedTypeDependent = { encoder: Name; +} + +interface NamedTypeDependent { decoder: Name; -}; + encoder: Name; +} export class ElmRenderer extends ConvenienceRenderer { private readonly _topLevelDependents = new Map(); + private readonly _namedTypeDependents = new Map(); - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return forbiddenNames; } - protected makeTopLevelDependencyNames(t: Type, topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames (t: Type, topLevelName: Name): DependencyName[] { const encoder = new DependencyName( lowerNamingFunction, topLevelName.order, - lookup => `${lookup(topLevelName)}_to_string` + lookup => `${lookup(topLevelName)}_to_string`, ); let decoder: DependencyName | undefined = undefined; if (this.namedTypeToNameForTopLevel(t) === undefined) { decoder = new DependencyName(lowerNamingFunction, topLevelName.order, lookup => lookup(topLevelName)); } + this._topLevelDependents.set(topLevelName, { encoder, decoder }); if (decoder !== undefined) { return [encoder, decoder]; } + return [encoder]; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return upperNamingFunction; } - protected makeNamedTypeDependencyNames(_: Type, typeName: Name): DependencyName[] { + protected makeNamedTypeDependencyNames (_: Type, typeName: Name): DependencyName[] { const encoder = new DependencyName(lowerNamingFunction, typeName.order, lookup => `encode_${lookup(typeName)}`); const decoder = new DependencyName(lowerNamingFunction, typeName.order, lookup => lookup(typeName)); this._namedTypeDependents.set(typeName, { encoder, decoder }); return [encoder, decoder]; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return lowerNamingFunction; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return upperNamingFunction; } - protected get unionMembersInGlobalNamespace(): boolean { + protected get unionMembersInGlobalNamespace (): boolean { return true; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return upperNamingFunction; } - protected get enumCasesInGlobalNamespace(): boolean { + protected get enumCasesInGlobalNamespace (): boolean { return true; } - protected proposeUnionMemberName( + protected proposeUnionMemberName ( u: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { const fieldName = super.proposeUnionMemberName(u, unionName, fieldType, lookup); return `${fieldName}_in_${lookup(unionName)}`; } - protected get commentLineStart(): string { + protected get commentLineStart (): string { return "-- "; } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { if (lines.length === 1) { this.emitComments([{ customLines: lines, lineStart: "{-| ", lineEnd: " -}" }]); } else { @@ -235,11 +246,11 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private get arrayType(): string { + private get arrayType (): string { return this._options.useList ? "List" : "Array"; } - private elmType(t: Type, noOptional = false): MultiWord { + private elmType (t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => singleWord(annotated(anyTypeIssueAnnotation, "Jdec.Value")), @@ -259,12 +270,13 @@ export class ElmRenderer extends ConvenienceRenderer { if (noOptional) return nullableType; return multiWord(" ", "Maybe", parenIfNeeded(nullableType)); } + return singleWord(this.nameForNamedType(unionType)); - } + }, ); } - private elmProperty(p: ClassProperty): Sourcelike { + private elmProperty (p: ClassProperty): Sourcelike { if (p.isOptional) { return multiWord(" ", "Maybe", parenIfNeeded(this.elmType(p.type, true))).source; } else { @@ -272,12 +284,12 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private decoderNameForNamedType(t: Type): Name { + private decoderNameForNamedType (t: Type): Name { const name = this.nameForNamedType(t); return defined(this._namedTypeDependents.get(name)).decoder; } - private decoderNameForType(t: Type, noOptional = false): MultiWord { + private decoderNameForType (t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => singleWord("Jdec.value"), @@ -290,7 +302,7 @@ export class ElmRenderer extends ConvenienceRenderer { multiWord( " ", ["Jdec.", decapitalize(this.arrayType)], - parenIfNeeded(this.decoderNameForType(arrayType.items)) + parenIfNeeded(this.decoderNameForType(arrayType.items)), ), classType => singleWord(this.decoderNameForNamedType(classType)), mapType => multiWord(" ", "Jdec.dict", parenIfNeeded(this.decoderNameForType(mapType.values))), @@ -302,12 +314,13 @@ export class ElmRenderer extends ConvenienceRenderer { if (noOptional) return nullableDecoder; return multiWord(" ", "Jdec.nullable", parenIfNeeded(nullableDecoder)); } + return singleWord(this.decoderNameForNamedType(unionType)); - } + }, ); } - private decoderNameForProperty(p: ClassProperty): MultiWord { + private decoderNameForProperty (p: ClassProperty): MultiWord { if (p.isOptional) { return multiWord(" ", "Jdec.nullable", parenIfNeeded(this.decoderNameForType(p.type, true))); } else { @@ -315,12 +328,12 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private encoderNameForNamedType(t: Type): Name { + private encoderNameForNamedType (t: Type): Name { const name = this.nameForNamedType(t); return defined(this._namedTypeDependents.get(name)).encoder; } - private encoderNameForType(t: Type, noOptional = false): MultiWord { + private encoderNameForType (t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => singleWord("identity"), @@ -333,7 +346,7 @@ export class ElmRenderer extends ConvenienceRenderer { multiWord( " ", ["make", this.arrayType, "Encoder"], - parenIfNeeded(this.encoderNameForType(arrayType.items)) + parenIfNeeded(this.encoderNameForType(arrayType.items)), ), classType => singleWord(this.encoderNameForNamedType(classType)), mapType => multiWord(" ", "makeDictEncoder", parenIfNeeded(this.encoderNameForType(mapType.values))), @@ -345,12 +358,13 @@ export class ElmRenderer extends ConvenienceRenderer { if (noOptional) return nullableEncoder; return multiWord(" ", "makeNullableEncoder", parenIfNeeded(nullableEncoder)); } + return singleWord(this.encoderNameForNamedType(unionType)); - } + }, ); } - private encoderNameForProperty(p: ClassProperty): MultiWord { + private encoderNameForProperty (p: ClassProperty): MultiWord { if (p.isOptional) { return multiWord(" ", "makeNullableEncoder", parenIfNeeded(this.encoderNameForType(p.type, true))); } else { @@ -358,11 +372,11 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private emitTopLevelDefinition(t: Type, topLevelName: Name): void { + private emitTopLevelDefinition (t: Type, topLevelName: Name): void { this.emitLine("type alias ", topLevelName, " = ", this.elmType(t).source); } - private emitClassDefinition(c: ClassType, className: Name): void { + private emitClassDefinition (c: ClassType, className: Name): void { let description = this.descriptionForType(c); this.forEachClassProperty(c, "none", (name, jsonName) => { const propertyDescription = this.descriptionForClassProperty(c, jsonName); @@ -373,6 +387,7 @@ export class ElmRenderer extends ConvenienceRenderer { } else { description.push(""); } + description.push(`${this.sourcelikeToString(name)}:`); description.push(...propertyDescription); }); @@ -388,11 +403,12 @@ export class ElmRenderer extends ConvenienceRenderer { if (onFirst) { this.emitLine("{"); } + this.emitLine("}"); }); } - private emitEnumDefinition(e: EnumType, enumName: Name): void { + private emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine("type ", enumName); this.indent(() => { @@ -405,7 +421,7 @@ export class ElmRenderer extends ConvenienceRenderer { }); } - private emitUnionDefinition(u: UnionType, unionName: Name): void { + private emitUnionDefinition (u: UnionType, unionName: Name): void { this.emitDescription(this.descriptionForType(u)); this.emitLine("type ", unionName); this.indent(() => { @@ -417,23 +433,25 @@ export class ElmRenderer extends ConvenienceRenderer { } else { this.emitLine(equalsOrPipe, " ", constructor, " ", parenIfNeeded(this.elmType(t))); } + onFirst = false; }); }); } - private emitTopLevelFunctions(t: Type, topLevelName: Name): void { + private emitTopLevelFunctions (t: Type, topLevelName: Name): void { const { encoder, decoder } = defined(this._topLevelDependents.get(topLevelName)); if (this.namedTypeToNameForTopLevel(t) === undefined) { this.emitLine(defined(decoder), " : Jdec.Decoder ", topLevelName); this.emitLine(defined(decoder), " = ", this.decoderNameForType(t).source); this.ensureBlankLine(); } + this.emitLine(encoder, " : ", topLevelName, " -> String"); this.emitLine(encoder, " r = Jenc.encode 0 (", this.encoderNameForType(t).source, " r)"); } - private emitClassFunctions(c: ClassType, className: Name): void { + private emitClassFunctions (c: ClassType, className: Name): void { const decoderName = this.decoderNameForNamedType(c); this.emitLine(decoderName, " : Jdec.Decoder ", className); this.emitLine(decoderName, " ="); @@ -443,7 +461,7 @@ export class ElmRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (_, jsonName, p) => { const propDecoder = parenIfNeeded(this.decoderNameForProperty(p)); const { reqOrOpt, fallback } = requiredOrOptional(p); - this.emitLine("|> ", reqOrOpt, ' "', stringEscape(jsonName), '" ', propDecoder, fallback); + this.emitLine("|> ", reqOrOpt, " \"", stringEscape(jsonName), "\" ", propDecoder, fallback); }); }); }); @@ -459,18 +477,19 @@ export class ElmRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const bracketOrComma = onFirst ? "[" : ","; const propEncoder = this.encoderNameForProperty(p).source; - this.emitLine(bracketOrComma, ' ("', stringEscape(jsonName), '", ', propEncoder, " x.", name, ")"); + this.emitLine(bracketOrComma, " (\"", stringEscape(jsonName), "\", ", propEncoder, " x.", name, ")"); onFirst = false; }); if (onFirst) { this.emitLine("["); } + this.emitLine("]"); }); }); } - private emitEnumFunctions(e: EnumType, enumName: Name): void { + private emitEnumFunctions (e: EnumType, enumName: Name): void { const decoderName = this.decoderNameForNamedType(e); this.emitLine(decoderName, " : Jdec.Decoder ", enumName); this.emitLine(decoderName, " ="); @@ -482,9 +501,9 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine("case str of"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine('"', stringEscape(jsonName), '" -> Jdec.succeed ', name); + this.emitLine("\"", stringEscape(jsonName), "\" -> Jdec.succeed ", name); }); - this.emitLine('somethingElse -> Jdec.fail <| "Invalid ', enumName, ': " ++ somethingElse'); + this.emitLine("somethingElse -> Jdec.fail <| \"Invalid ", enumName, ": \" ++ somethingElse"); }); }); this.emitLine(")"); @@ -497,14 +516,14 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine(encoderName, " x = case x of"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine(name, ' -> Jenc.string "', stringEscape(jsonName), '"'); + this.emitLine(name, " -> Jenc.string \"", stringEscape(jsonName), "\""); }); }); } - private emitUnionFunctions(u: UnionType, unionName: Name): void { + private emitUnionFunctions (u: UnionType, unionName: Name): void { // We need arrays first, then strings, and integers before doubles. - function sortOrder(_: Name, t: Type): string { + function sortOrder (_: Name, t: Type): string { if (t.kind === "array") { return " array"; } else if (t.kind === "double") { @@ -512,6 +531,7 @@ export class ElmRenderer extends ConvenienceRenderer { } else if (t.isPrimitive()) { return " " + t.kind; } + return t.kind; } @@ -530,6 +550,7 @@ export class ElmRenderer extends ConvenienceRenderer { const decoder = parenIfNeeded(this.decoderNameForType(t)); this.emitLine(bracketOrComma, " Jdec.map ", constructor, " ", decoder); } + onFirst = false; }); this.emitLine("]"); @@ -552,7 +573,7 @@ export class ElmRenderer extends ConvenienceRenderer { }); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { const exports: Sourcelike[] = []; const topLevelDecoders: Sourcelike[] = []; this.forEachTopLevel("none", (_, name) => { @@ -560,6 +581,7 @@ export class ElmRenderer extends ConvenienceRenderer { if (decoder === undefined) { decoder = defined(this._namedTypeDependents.get(name)).decoder; } + topLevelDecoders.push(decoder); exports.push(name, encoder, decoder); }); @@ -583,14 +605,14 @@ export class ElmRenderer extends ConvenienceRenderer { "", "add these imports", "", - " import Json.Decode exposing (decodeString)`);" + " import Json.Decode exposing (decodeString)`);", ]); this.emitLine( "-- import ", this._options.moduleName, " exposing (", arrayIntercalate(", ", topLevelDecoders), - ")" + ")", ); this.emitMultiline(`-- -- and you're off to the races with @@ -600,6 +622,7 @@ export class ElmRenderer extends ConvenienceRenderer { if (decoder === undefined) { decoder = defined(this._namedTypeDependents.get(name)).decoder; } + this.emitLine("-- decodeString ", decoder, " myJsonString"); }); } @@ -611,6 +634,7 @@ export class ElmRenderer extends ConvenienceRenderer { for (let i = 0; i < exports.length; i++) { this.emitLine(i === 0 ? "(" : ",", " ", exports[i]); } + this.emitLine(")"); }); this.ensureBlankLine(); @@ -629,13 +653,13 @@ import Dict exposing (Dict, map, toList)`); this.forEachTopLevel( "leading-and-interposing", (t: Type, topLevelName: Name) => this.emitTopLevelDefinition(t, topLevelName), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassDefinition(c, className), (e: EnumType, enumName: Name) => this.emitEnumDefinition(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName) + (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName), ); if (this._options.justTypes) return; @@ -643,13 +667,13 @@ import Dict exposing (Dict, map, toList)`); this.ensureBlankLine(); this.emitLine("-- decoders and encoders"); this.forEachTopLevel("leading-and-interposing", (t: Type, topLevelName: Name) => - this.emitTopLevelFunctions(t, topLevelName) + this.emitTopLevelFunctions(t, topLevelName), ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassFunctions(c, className), (e: EnumType, enumName: Name) => this.emitEnumFunctions(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName) + (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName), ); this.ensureBlankLine(); diff --git a/packages/quicktype-core/src/language/Golang.ts b/packages/quicktype-core/src/language/Golang.ts index 847bb075d..c41a6af26 100644 --- a/packages/quicktype-core/src/language/Golang.ts +++ b/packages/quicktype-core/src/language/Golang.ts @@ -1,6 +1,8 @@ -import { TypeKind, Type, ClassType, EnumType, UnionType, ClassProperty } from "../Type"; +import { type TypeKind, type Type, type ClassType, type EnumType, type ClassProperty } from "../Type"; +import { UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { Name, DependencyName, Namer, funPrefixNamer } from "../Naming"; +import { type Name, type Namer} from "../Naming"; +import { DependencyName, funPrefixNamer } from "../Naming"; import { legalizeCharacters, isLetterOrUnderscore, @@ -10,16 +12,18 @@ import { combineWords, firstUpperWordStyle, allUpperWordStyle, - camelCase + camelCase, } from "../support/Strings"; import { assert, defined } from "../support/Support"; -import { StringOption, BooleanOption, Option, OptionValues, getOptionValues } from "../RendererOptions"; -import { Sourcelike, maybeAnnotated, modifySource } from "../Source"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { StringOption, BooleanOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated, modifySource } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { TargetLanguage } from "../TargetLanguage"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { RenderContext } from "../Renderer"; -import { StringTypeMapping, TransformedStringTypeKind, PrimitiveStringTypeKind } from ".."; +import { type RenderContext } from "../Renderer"; +import { type StringTypeMapping, type TransformedStringTypeKind, type PrimitiveStringTypeKind } from ".."; export const goOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), @@ -29,46 +33,46 @@ export const goOptions = { fieldTags: new StringOption("field-tags", "list of tags which should be generated for fields", "TAGS", "json"), omitEmpty: new BooleanOption( "omit-empty", - 'If set, all non-required objects will be tagged with ",omitempty"', - false - ) + "If set, all non-required objects will be tagged with \",omitempty\"", + false, + ), }; export class GoTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Go", ["go", "golang"], "go"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ goOptions.justTypes, goOptions.justTypesAndPackage, goOptions.packageName, goOptions.multiFileOutput, goOptions.fieldTags, - goOptions.omitEmpty + goOptions.omitEmpty, ]; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date-time", "date-time"); return mapping; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): GoRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): GoRenderer { return new GoRenderer(this, renderContext, getOptionValues(goOptions, untypedOptionValues)); } - protected get defaultIndentation(): string { + protected get defaultIndentation (): string { return "\t"; } } @@ -77,7 +81,7 @@ const namingFunction = funPrefixNamer("namer", goNameStyle); const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); -function goNameStyle(original: string): string { +function goNameStyle (original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -87,69 +91,70 @@ function goNameStyle(original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } const primitiveValueTypeKinds: TypeKind[] = ["integer", "double", "bool", "string"]; const compoundTypeKinds: TypeKind[] = ["array", "class", "map", "enum"]; -function isValueType(t: Type): boolean { +function isValueType (t: Type): boolean { const kind = t.kind; - return primitiveValueTypeKinds.indexOf(kind) >= 0 || kind === "class" || kind === "enum" || kind === "date-time"; + return primitiveValueTypeKinds.includes(kind) || kind === "class" || kind === "enum" || kind === "date-time"; } -function canOmitEmpty(cp: ClassProperty, omitEmptyOption: boolean): boolean { +function canOmitEmpty (cp: ClassProperty, omitEmptyOption: boolean): boolean { if (!cp.isOptional) return false; if (omitEmptyOption) return true; const t = cp.type; - return ["union", "null", "any"].indexOf(t.kind) < 0; + return !["union", "null", "any"].includes(t.kind); } export class GoRenderer extends ConvenienceRenderer { private readonly _topLevelUnmarshalNames = new Map(); + private _currentFilename: string | undefined; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return namingFunction; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return namingFunction; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return namingFunction; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return namingFunction; } - protected get enumCasesInGlobalNamespace(): boolean { + protected get enumCasesInGlobalNamespace (): boolean { return true; } - protected makeTopLevelDependencyNames(_: Type, topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames (_: Type, topLevelName: Name): DependencyName[] { const unmarshalName = new DependencyName( namingFunction, topLevelName.order, - lookup => `unmarshal_${lookup(topLevelName)}` + lookup => `unmarshal_${lookup(topLevelName)}`, ); this._topLevelUnmarshalNames.set(topLevelName, unmarshalName); return [unmarshalName]; } /// startFile takes a file name, lowercases it, appends ".go" to it, and sets it as the current filename. - protected startFile(basename: Sourcelike): void { + protected startFile (basename: Sourcelike): void { if (this._options.multiFileOutput === false) { return; } @@ -160,7 +165,7 @@ export class GoRenderer extends ConvenienceRenderer { } /// endFile pushes the current file name onto the collection of finished files and then resets the current file name. These finished files are used in index.ts to write the output. - protected endFile(): void { + protected endFile (): void { if (this._options.multiFileOutput === false) { return; } @@ -169,21 +174,21 @@ export class GoRenderer extends ConvenienceRenderer { this._currentFilename = undefined; } - private emitBlock(line: Sourcelike, f: () => void): void { + private emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - private emitFunc(decl: Sourcelike, f: () => void): void { + private emitFunc (decl: Sourcelike, f: () => void): void { this.emitBlock(["func ", decl], f); } - private emitStruct(name: Name, table: Sourcelike[][]): void { + private emitStruct (name: Name, table: Sourcelike[][]): void { this.emitBlock(["type ", name, " struct"], () => this.emitTable(table)); } - private nullableGoType(t: Type, withIssues: boolean): Sourcelike { + private nullableGoType (t: Type, withIssues: boolean): Sourcelike { const goType = this.goType(t, withIssues); if (isValueType(t)) { return ["*", goType]; @@ -192,18 +197,20 @@ export class GoRenderer extends ConvenienceRenderer { } } - private propertyGoType(cp: ClassProperty): Sourcelike { + private propertyGoType (cp: ClassProperty): Sourcelike { const t = cp.type; if (t instanceof UnionType && nullableFromUnion(t) === null) { return ["*", this.goType(t, true)]; } + if (cp.isOptional) { return this.nullableGoType(t, true); } + return this.goType(t, true); } - private goType(t: Type, withIssues = false): Sourcelike { + private goType (t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "interface{}"), @@ -222,6 +229,7 @@ export class GoRenderer extends ConvenienceRenderer { } else { valueSource = this.goType(v, withIssues); } + return ["map[string]", valueSource]; }, enumType => this.nameForNamedType(enumType), @@ -236,11 +244,11 @@ export class GoRenderer extends ConvenienceRenderer { } return "string"; - } + }, ); } - private emitTopLevel(t: Type, name: Name): void { + private emitTopLevel (t: Type, name: Name): void { this.startFile(name); if ( @@ -250,7 +258,7 @@ export class GoRenderer extends ConvenienceRenderer { this.leadingComments === undefined ) { this.emitLineOnce( - "// This file was generated from JSON Schema using quicktype, do not modify it directly." + "// This file was generated from JSON Schema using quicktype, do not modify it directly.", ); this.emitLineOnce("// To parse and unparse this JSON data, add this code to your project and do:"); this.emitLineOnce("//"); @@ -281,7 +289,7 @@ export class GoRenderer extends ConvenienceRenderer { this.endFile(); } - private emitClass(c: ClassType, className: Name): void { + private emitClass (c: ClassType, className: Name): void { this.startFile(className); let columns: Sourcelike[][] = []; const usedTypes = new Set(); @@ -295,12 +303,12 @@ export class GoRenderer extends ConvenienceRenderer { docStrings.forEach(doc => columns.push([doc])); const tags = this._options.fieldTags .split(",") - .map(tag => tag + ':"' + stringEscape(jsonName) + omitEmpty + '"') + .map(tag => tag + ":\"" + stringEscape(jsonName) + omitEmpty + "\"") .join(" "); columns.push([ [name, " "], [goType, " "], - ["`", tags, "`"] + ["`", tags, "`"], ]); usedTypes.add(goType.toString()); }); @@ -309,14 +317,14 @@ export class GoRenderer extends ConvenienceRenderer { false, usedTypes.has("time.Time") || usedTypes.has("*,time.Time") || usedTypes.has("[],time.Time") ? new Set(["time"]) - : undefined + : undefined, ); this.emitDescription(this.descriptionForType(c)); this.emitStruct(className, columns); this.endFile(); } - private emitEnum(e: EnumType, enumName: Name): void { + private emitEnum (e: EnumType, enumName: Name): void { this.startFile(enumName); this.emitPackageDefinitons(false); this.emitDescription(this.descriptionForType(e)); @@ -327,7 +335,7 @@ export class GoRenderer extends ConvenienceRenderer { this.forEachEnumCase(e, "none", (name, jsonName) => { columns.push([ [name, " "], - [enumName, ' = "', stringEscape(jsonName), '"'] + [enumName, " = \"", stringEscape(jsonName), "\""], ]); }); this.indent(() => this.emitTable(columns)); @@ -335,7 +343,7 @@ export class GoRenderer extends ConvenienceRenderer { this.endFile(); } - private emitUnion(u: UnionType, unionName: Name): void { + private emitUnion (u: UnionType, unionName: Name): void { this.startFile(unionName); this.emitPackageDefinitons(false); const [hasNull, nonNulls] = removeNullFromUnion(u); @@ -356,23 +364,26 @@ export class GoRenderer extends ConvenienceRenderer { this.emitLine("x.", fieldName, " = nil"); }); }; + const makeArgs = ( primitiveArg: (fieldName: Sourcelike) => Sourcelike, - compoundArg: (isClass: boolean, fieldName: Sourcelike) => Sourcelike + compoundArg: (isClass: boolean, fieldName: Sourcelike) => Sourcelike, ): Sourcelike => { const args: Sourcelike = []; for (const kind of primitiveValueTypeKinds) { args.push( ifMember(kind, "nil", (_1, fieldName, _2) => primitiveArg(fieldName)), - ", " + ", ", ); } + for (const kind of compoundTypeKinds) { args.push( ifMember(kind, "false, nil", (t, fieldName, _) => compoundArg(t.kind === "class", fieldName)), - ", " + ", ", ); } + args.push(isNullableArg); return args; }; @@ -392,6 +403,7 @@ export class GoRenderer extends ConvenienceRenderer { for (const kind of compoundTypeKinds) { maybeAssignNil(kind); } + ifMember("class", undefined, (_1, _2, goType) => { this.emitLine("var c ", goType); }); @@ -403,7 +415,7 @@ export class GoRenderer extends ConvenienceRenderer { } else { return ["true, &x.", fn]; } - } + }, ); this.emitLine("object, err := unmarshalUnion(data, ", args, ")"); this.emitBlock("if err != nil", () => { @@ -420,14 +432,14 @@ export class GoRenderer extends ConvenienceRenderer { this.emitFunc(["(x *", unionName, ") MarshalJSON() ([]byte, error)"], () => { const args = makeArgs( fn => ["x.", fn], - (_, fn) => ["x.", fn, " != nil, x.", fn] + (_, fn) => ["x.", fn, " != nil, x.", fn], ); this.emitLine("return marshalUnion(", args, ")"); }); this.endFile(); } - private emitSingleFileHeaderComments(): void { + private emitSingleFileHeaderComments (): void { this.emitLineOnce("// This file was generated from JSON Schema using quicktype, do not modify it directly."); this.emitLineOnce("// To parse and unparse this JSON data, add this code to your project and do:"); this.forEachTopLevel("none", (_: Type, name: Name) => { @@ -438,7 +450,7 @@ export class GoRenderer extends ConvenienceRenderer { }); } - private emitPackageDefinitons(includeJSONEncodingImport: boolean, imports: Set = new Set()): void { + private emitPackageDefinitons (includeJSONEncodingImport: boolean, imports: Set = new Set()): void { if (!this._options.justTypes || this._options.justTypesAndPackage) { this.ensureBlankLine(); const packageDeclaration = "package " + this._options.packageName; @@ -460,7 +472,7 @@ export class GoRenderer extends ConvenienceRenderer { this.emitImports(imports); } - private emitImports(imports: Set): void { + private emitImports (imports: Set): void { const sortedImports = Array.from(imports).sort((a, b) => a.localeCompare(b)); if (sortedImports.length === 0) { @@ -473,7 +485,7 @@ export class GoRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - private emitHelperFunctions(): void { + private emitHelperFunctions (): void { if (this.haveNamedUnions) { this.startFile("JSONSchemaSupport"); const imports = new Set(); @@ -602,7 +614,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, } } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { if ( this._options.multiFileOutput === false && this._options.justTypes === false && @@ -618,7 +630,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, (t, name) => this.emitTopLevel(t, name), t => !(this._options.justTypes || this._options.justTypesAndPackage) || - this.namedTypeToNameForTopLevel(t) === undefined + this.namedTypeToNameForTopLevel(t) === undefined, ); this.forEachObject("leading-and-interposing", (c: ClassType, className: Name) => this.emitClass(c, className)); this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => this.emitEnum(u, enumName)); @@ -631,7 +643,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, this.emitHelperFunctions(); } - private collectAllImports(): Set { + private collectAllImports (): Set { let imports = new Set(); this.forEachObject("leading-and-interposing", (c: ClassType, _className: Name) => { const classImports = this.collectClassImports(c); @@ -645,7 +657,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, return imports; } - private collectClassImports(c: ClassType): Set { + private collectClassImports (c: ClassType): Set { const usedTypes = new Set(); const mapping: Map = new Map(); mapping.set("time.Time", "time"); @@ -668,7 +680,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, return imports; } - private collectUnionImports(u: UnionType): Set { + private collectUnionImports (u: UnionType): Set { const usedTypes = new Set(); const mapping: Map = new Map(); mapping.set("time.Time", "time"); diff --git a/packages/quicktype-core/src/language/Haskell.ts b/packages/quicktype-core/src/language/Haskell.ts index 2bac412e9..ed13a8ee7 100644 --- a/packages/quicktype-core/src/language/Haskell.ts +++ b/packages/quicktype-core/src/language/Haskell.ts @@ -1,10 +1,13 @@ import { mapContains } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { EnumOption, StringOption, BooleanOption, Option, getOptionValues, OptionValues } from "../RendererOptions"; -import { Type, ClassType, UnionType, EnumType, ClassProperty } from "../Type"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { EnumOption, StringOption, BooleanOption, getOptionValues } from "../RendererOptions"; +import { type Type, type ClassType, type UnionType, type EnumType, type ClassProperty } from "../Type"; import { matchType, nullableFromUnion } from "../TypeUtils"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { Namer, Name, funPrefixNamer } from "../Naming"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Namer, type Name} from "../Naming"; +import { funPrefixNamer } from "../Naming"; import { legalizeCharacters, isLetterOrUnderscoreOrDigit, @@ -15,40 +18,41 @@ import { combineWords, firstUpperWordStyle, allLowerWordStyle, - allUpperWordStyle + allUpperWordStyle, } from "../support/Strings"; -import { Sourcelike, MultiWord, singleWord, multiWord, parenIfNeeded } from "../Source"; -import { RenderContext } from "../Renderer"; +import { type Sourcelike, type MultiWord} from "../Source"; +import { singleWord, multiWord, parenIfNeeded } from "../Source"; +import { type RenderContext } from "../Renderer"; export const haskellOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), useList: new EnumOption("array-type", "Use Array or List", [ ["array", false], - ["list", true] + ["list", true], ]), - moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") + moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType"), }; export class HaskellTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Haskell", ["haskell"], "haskell"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [haskellOptions.justTypes, haskellOptions.moduleName, haskellOptions.useList]; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): HaskellRenderer { return new HaskellRenderer(this, renderContext, getOptionValues(haskellOptions, untypedOptionValues)); } @@ -106,12 +110,12 @@ const forbiddenNames = [ "Object", "Result", "Series", - "Error" + "Error", ]; const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); -function haskellNameStyle(original: string, upper: boolean): string { +function haskellNameStyle (original: string, upper: boolean): string { const words = splitIntoWords(original); return combineWords( words, @@ -121,7 +125,7 @@ function haskellNameStyle(original: string, upper: boolean): string { upper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } @@ -129,73 +133,73 @@ const upperNamingFunction = funPrefixNamer("upper", n => haskellNameStyle(n, tru const lowerNamingFunction = funPrefixNamer("lower", n => haskellNameStyle(n, false)); export class HaskellRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return forbiddenNames; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return upperNamingFunction; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return lowerNamingFunction; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return upperNamingFunction; } - protected get unionMembersInGlobalNamespace(): boolean { + protected get unionMembersInGlobalNamespace (): boolean { return true; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return upperNamingFunction; } - protected get enumCasesInGlobalNamespace(): boolean { + protected get enumCasesInGlobalNamespace (): boolean { return true; } - protected proposeUnionMemberName( + protected proposeUnionMemberName ( u: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { const fieldName = super.proposeUnionMemberName(u, unionName, fieldType, lookup); return `${fieldName}_in_${lookup(unionName)}`; } - protected get commentLineStart(): string { + protected get commentLineStart (): string { return "-- "; } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { if (lines.length === 1) { this.emitComments([{ customLines: lines, lineStart: "{-| ", lineEnd: " -}" }]); } else { this.emitCommentLines(lines, { firstLineStart: "{-| ", lineStart: "", - afterComment: "-}" + afterComment: "-}", }); } } - private haskellType(t: Type, noOptional = false): MultiWord { + private haskellType (t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => multiWord(" ", "Maybe", "Text"), @@ -208,6 +212,7 @@ export class HaskellRenderer extends ConvenienceRenderer { if (this._options.useList) { return multiWord("", "[", parenIfNeeded(this.haskellType(arrayType.items)), "]"); } + return multiWord(" ", "Vector", parenIfNeeded(this.haskellType(arrayType.items))); }, classType => singleWord(this.nameForNamedType(classType)), @@ -220,12 +225,13 @@ export class HaskellRenderer extends ConvenienceRenderer { if (noOptional) return nullableType; return multiWord(" ", "Maybe", parenIfNeeded(nullableType)); } + return singleWord(this.nameForNamedType(unionType)); - } + }, ); } - private haskellProperty(p: ClassProperty): Sourcelike { + private haskellProperty (p: ClassProperty): Sourcelike { if (p.isOptional) { return multiWord(" ", "Maybe", parenIfNeeded(this.haskellType(p.type, true))).source; } else { @@ -233,7 +239,7 @@ export class HaskellRenderer extends ConvenienceRenderer { } } - private encoderNameForType(t: Type): MultiWord { + private encoderNameForType (t: Type): MultiWord { return matchType( t, _anyType => singleWord("String"), @@ -246,15 +252,15 @@ export class HaskellRenderer extends ConvenienceRenderer { _classType => singleWord("Object"), _mapType => singleWord("Object"), _enumType => singleWord("Object"), - _unionType => singleWord("Object") + _unionType => singleWord("Object"), ); } - private emitTopLevelDefinition(t: Type, topLevelName: Name): void { + private emitTopLevelDefinition (t: Type, topLevelName: Name): void { this.emitLine("type ", topLevelName, " = ", this.haskellType(t).source); } - private emitClassDefinition(c: ClassType, className: Name): void { + private emitClassDefinition (c: ClassType, className: Name): void { let description = this.descriptionForType(c); this.forEachClassProperty(c, "none", (name, jsonName) => { const propertyDescription = this.descriptionForClassProperty(c, jsonName); @@ -265,6 +271,7 @@ export class HaskellRenderer extends ConvenienceRenderer { } else { description.push(""); } + description.push(`${this.sourcelikeToString(name)}:`); description.push(...propertyDescription); }); @@ -280,11 +287,12 @@ export class HaskellRenderer extends ConvenienceRenderer { if (onFirst) { this.emitLine("{"); } + this.emitLine("} deriving (Show)"); }); } - private emitEnumDefinition(e: EnumType, enumName: Name): void { + private emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine("data ", enumName); this.indent(() => { @@ -298,7 +306,7 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitUnionDefinition(u: UnionType, unionName: Name): void { + private emitUnionDefinition (u: UnionType, unionName: Name): void { this.emitDescription(this.descriptionForType(u)); this.emitLine("data ", unionName); this.indent(() => { @@ -310,18 +318,19 @@ export class HaskellRenderer extends ConvenienceRenderer { } else { this.emitLine(equalsOrPipe, " ", constructor, " ", parenIfNeeded(this.haskellType(t))); } + onFirst = false; }); this.emitLine("deriving (Show)"); }); } - private emitTopLevelFunctions(topLevelName: Name): void { + private emitTopLevelFunctions (topLevelName: Name): void { this.emitLine("decodeTopLevel :: ByteString -> Maybe ", topLevelName); this.emitLine("decodeTopLevel = decode"); } - private classPropertyLength(c: ClassType): number { + private classPropertyLength (c: ClassType): number { let counter = 0; this.forEachClassProperty(c, "none", () => { counter += 1; @@ -329,7 +338,7 @@ export class HaskellRenderer extends ConvenienceRenderer { return counter; } - private emitClassEncoderInstance(c: ClassType, className: Name): void { + private emitClassEncoderInstance (c: ClassType, className: Name): void { let classProperties: Array = []; this.forEachClassProperty(c, "none", name => { classProperties.push(" "); @@ -347,19 +356,20 @@ export class HaskellRenderer extends ConvenienceRenderer { this.emitLine("object"); let onFirst = true; this.forEachClassProperty(c, "none", (name, jsonName) => { - this.emitLine(onFirst ? "[ " : ", ", '"', stringEscape(jsonName), '" .= ', name, className); + this.emitLine(onFirst ? "[ " : ", ", "\"", stringEscape(jsonName), "\" .= ", name, className); onFirst = false; }); if (onFirst) { this.emitLine("["); } + this.emitLine("]"); }); } }); } - private emitClassDecoderInstance(c: ClassType, className: Name): void { + private emitClassDecoderInstance (c: ClassType, className: Name): void { this.emitLine("instance FromJSON ", className, " where"); this.indent(() => { @@ -371,7 +381,7 @@ export class HaskellRenderer extends ConvenienceRenderer { let onFirst = true; this.forEachClassProperty(c, "none", (_, jsonName, p) => { const operator = p.isOptional ? ".:?" : ".:"; - this.emitLine(onFirst ? "<$> " : "<*> ", "v ", operator, ' "', stringEscape(jsonName), '"'); + this.emitLine(onFirst ? "<$> " : "<*> ", "v ", operator, " \"", stringEscape(jsonName), "\""); onFirst = false; }); }); @@ -379,43 +389,43 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitClassFunctions(c: ClassType, className: Name): void { + private emitClassFunctions (c: ClassType, className: Name): void { this.emitClassEncoderInstance(c, className); this.ensureBlankLine(); this.emitClassDecoderInstance(c, className); } - private emitEnumEncoderInstance(e: EnumType, enumName: Name): void { + private emitEnumEncoderInstance (e: EnumType, enumName: Name): void { this.emitLine("instance ToJSON ", enumName, " where"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("toJSON ", name, enumName, ' = "', stringEscape(jsonName), '"'); + this.emitLine("toJSON ", name, enumName, " = \"", stringEscape(jsonName), "\""); }); }); } - private emitEnumDecoderInstance(e: EnumType, enumName: Name): void { + private emitEnumDecoderInstance (e: EnumType, enumName: Name): void { this.emitLine("instance FromJSON ", enumName, " where"); this.indent(() => { - this.emitLine('parseJSON = withText "', enumName, '" parseText'); + this.emitLine("parseJSON = withText \"", enumName, "\" parseText"); this.indent(() => { this.emitLine("where"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine('parseText "', stringEscape(jsonName), '" = return ', name, enumName); + this.emitLine("parseText \"", stringEscape(jsonName), "\" = return ", name, enumName); }); }); }); }); } - private emitEnumFunctions(e: EnumType, enumName: Name): void { + private emitEnumFunctions (e: EnumType, enumName: Name): void { this.emitEnumEncoderInstance(e, enumName); this.ensureBlankLine(); this.emitEnumDecoderInstance(e, enumName); } - private emitUnionEncoderInstance(u: UnionType, unionName: Name): void { + private emitUnionEncoderInstance (u: UnionType, unionName: Name): void { this.emitLine("instance ToJSON ", unionName, " where"); this.indent(() => { this.forEachUnionMember(u, null, "none", null, (constructor, t) => { @@ -428,7 +438,7 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitUnionDecoderInstance(u: UnionType, unionName: Name): void { + private emitUnionDecoderInstance (u: UnionType, unionName: Name): void { this.emitLine("instance FromJSON ", unionName, " where"); this.indent(() => { this.forEachUnionMember(u, null, "none", null, (constructor, t) => { @@ -440,24 +450,24 @@ export class HaskellRenderer extends ConvenienceRenderer { this.encoderNameForType(t).source, " _) = (fmap ", constructor, - " . parseJSON) xs" + " . parseJSON) xs", ); } }); }); } - private emitUnionFunctions(u: UnionType, unionName: Name): void { + private emitUnionFunctions (u: UnionType, unionName: Name): void { this.emitUnionEncoderInstance(u, unionName); this.ensureBlankLine(); this.emitUnionDecoderInstance(u, unionName); } - private emitLanguageExtensions(ext: string): void { + private emitLanguageExtensions (ext: string): void { this.emitLine(`{-# LANGUAGE ${ext} #-}`); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { const exports: Sourcelike[] = []; this.forEachTopLevel("none", (_, name) => { exports.push([name, " (..)"]); @@ -482,6 +492,7 @@ export class HaskellRenderer extends ConvenienceRenderer { for (let i = 0; i < exports.length; i++) { this.emitLine(i === 0 ? "(" : ",", " ", exports[i]); } + this.emitLine(", decodeTopLevel"); this.emitLine(") where"); }); @@ -501,25 +512,25 @@ import Data.Text (Text)`); this.forEachTopLevel( "leading-and-interposing", (t: Type, topLevelName: Name) => this.emitTopLevelDefinition(t, topLevelName), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassDefinition(c, className), (e: EnumType, enumName: Name) => this.emitEnumDefinition(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName) + (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName), ); this.forEachTopLevel("leading-and-interposing", (_: Type, topLevelName: Name) => - this.emitTopLevelFunctions(topLevelName) + this.emitTopLevelFunctions(topLevelName), ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassFunctions(c, className), (e: EnumType, enumName: Name) => this.emitEnumFunctions(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName) + (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName), ); if (this._options.justTypes) return; diff --git a/packages/quicktype-core/src/language/JSONSchema.ts b/packages/quicktype-core/src/language/JSONSchema.ts index 2b8a447ba..c18d6c744 100644 --- a/packages/quicktype-core/src/language/JSONSchema.ts +++ b/packages/quicktype-core/src/language/JSONSchema.ts @@ -1,47 +1,50 @@ import { mapFirst, iterableFirst } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { Type, UnionType, EnumType, ObjectType, transformedStringTypeTargetTypeKindsMap } from "../Type"; +import { type Type, type UnionType, type EnumType, type ObjectType} from "../Type"; +import { transformedStringTypeTargetTypeKindsMap } from "../Type"; import { matchTypeExhaustive } from "../TypeUtils"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { Namer, funPrefixNamer, Name } from "../Naming"; +import { type Namer, type Name } from "../Naming"; +import { funPrefixNamer } from "../Naming"; import { legalizeCharacters, splitIntoWords, combineWords, firstUpperWordStyle, - allUpperWordStyle + allUpperWordStyle, } from "../support/Strings"; import { defined, panic } from "../support/Support"; -import { StringTypeMapping, getNoStringTypeMapping } from "../TypeBuilder"; +import { type StringTypeMapping} from "../TypeBuilder"; +import { getNoStringTypeMapping } from "../TypeBuilder"; import { addDescriptionToSchema } from "../attributes/Description"; -import { Option } from "../RendererOptions"; -import { RenderContext } from "../Renderer"; +import { type Option } from "../RendererOptions"; +import { type RenderContext } from "../Renderer"; export class JSONSchemaTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("JSON Schema", ["schema", "json-schema"], "schema"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return []; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { return getNoStringTypeMapping(); } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsFullObjectType(): boolean { + get supportsFullObjectType (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - _untypedOptionValues: { [name: string]: any } + _untypedOptionValues: { [name: string]: any, }, ): JSONSchemaRenderer { return new JSONSchemaRenderer(this, renderContext); } @@ -51,7 +54,7 @@ const namingFunction = funPrefixNamer("namer", jsonNameStyle); const legalizeName = legalizeCharacters(cp => cp >= 32 && cp < 128 && cp !== 0x2f /* slash */); -function jsonNameStyle(original: string): string { +function jsonNameStyle (original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -61,57 +64,61 @@ function jsonNameStyle(original: string): string { allUpperWordStyle, allUpperWordStyle, "", - _ => true + _ => true, ); } -type Schema = { [name: string]: any }; +interface Schema { + [name: string]: any; +} export class JSONSchemaRenderer extends ConvenienceRenderer { - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return namingFunction; } - protected namerForObjectProperty(): null { + protected namerForObjectProperty (): null { return null; } - protected makeUnionMemberNamer(): null { + protected makeUnionMemberNamer (): null { return null; } - protected makeEnumCaseNamer(): null { + protected makeEnumCaseNamer (): null { return null; } - private nameForType(t: Type): string { + private nameForType (t: Type): string { return defined(this.names.get(this.nameForNamedType(t))); } - private makeOneOf(types: ReadonlySet): Schema { + private makeOneOf (types: ReadonlySet): Schema { const first = iterableFirst(types); if (first === undefined) { return panic("Must have at least one type for oneOf"); } + if (types.size === 1) { return this.schemaForType(first); } + return { anyOf: Array.from(types).map((t: Type) => this.schemaForType(t)) }; } - private makeRef(t: Type): Schema { + private makeRef (t: Type): Schema { return { $ref: `#/definitions/${this.nameForType(t)}` }; } - private addAttributesToSchema(t: Type, schema: Schema): void { + private addAttributesToSchema (t: Type, schema: Schema): void { const attributes = this.typeGraph.attributeStore.attributesForType(t); for (const [kind, attr] of attributes) { kind.addToSchema(schema, t, attr); } } - private schemaForType(t: Type): Schema { - const schema = matchTypeExhaustive<{ [name: string]: any }>( + private schemaForType (t: Type): Schema { + const schema = matchTypeExhaustive<{ [name: string]: any, }>( t, _noneType => { return panic("none type should have been replaced"); @@ -139,16 +146,18 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { if (target === undefined) { return panic(`Unknown transformed string type ${transformedStringType.kind}`); } + return { type: "string", format: target.jsonSchema }; - } + }, ); if (schema.$ref === undefined) { this.addAttributesToSchema(t, schema); } + return schema; } - private definitionForObject(o: ObjectType, title: string | undefined): Schema { + private definitionForObject (o: ObjectType, title: string | undefined): Schema { let properties: Schema | undefined; let required: string[] | undefined; if (o.getProperties().size === 0) { @@ -162,14 +171,17 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { if (prop.description === undefined) { addDescriptionToSchema(prop, this.descriptionForClassProperty(o, name)); } + props[name] = prop; if (!p.isOptional) { req.push(name); } } + properties = props; required = req.sort(); } + const additional = o.getAdditionalProperties(); const additionalProperties = additional !== undefined ? this.schemaForType(additional) : false; const schema = { @@ -177,32 +189,33 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { additionalProperties, properties, required, - title + title, }; this.addAttributesToSchema(o, schema); return schema; } - private definitionForUnion(u: UnionType, title?: string): Schema { + private definitionForUnion (u: UnionType, title?: string): Schema { const oneOf = this.makeOneOf(u.sortedMembers); if (title !== undefined) { oneOf.title = title; } + this.addAttributesToSchema(u, oneOf); return oneOf; } - private definitionForEnum(e: EnumType, title: string): Schema { + private definitionForEnum (e: EnumType, title: string): Schema { const schema = { type: "string", enum: Array.from(e.cases), title }; this.addAttributesToSchema(e, schema); return schema; } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { // FIXME: Find a good way to do multiple top-levels. Maybe multiple files? const topLevelType = this.topLevels.size === 1 ? this.schemaForType(defined(mapFirst(this.topLevels))) : {}; const schema = Object.assign({ $schema: "http://json-schema.org/draft-06/schema#" }, topLevelType); - const definitions: { [name: string]: Schema } = {}; + const definitions: { [name: string]: Schema, } = {}; this.forEachObject("none", (o: ObjectType, name: Name) => { const title = defined(this.names.get(name)); definitions[title] = this.definitionForObject(o, title); diff --git a/packages/quicktype-core/src/language/Java.ts b/packages/quicktype-core/src/language/Java.ts index 05ad4b535..a4cc006d1 100644 --- a/packages/quicktype-core/src/language/Java.ts +++ b/packages/quicktype-core/src/language/Java.ts @@ -1,9 +1,13 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { DependencyName, funPrefixNamer, Name, Namer } from "../Naming"; -import { RenderContext } from "../Renderer"; -import { BooleanOption, EnumOption, getOptionValues, Option, OptionValues, StringOption } from "../RendererOptions"; -import { maybeAnnotated, Sourcelike } from "../Source"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer } from "../Naming"; +import { DependencyName, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { BooleanOption, EnumOption, getOptionValues, StringOption } from "../RendererOptions"; +import { type Sourcelike } from "../Source"; +import { maybeAnnotated } from "../Source"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; import { allLowerWordStyle, @@ -18,13 +22,14 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../support/Strings"; import { assert, assertNever, defined, panic } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, ClassProperty, ClassType, EnumType, MapType, Type, TypeKind, UnionType } from "../Type"; +import { type ClassProperty, type Type, type TypeKind} from "../Type"; +import { ArrayType, ClassType, EnumType, MapType, UnionType } from "../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { StringTypeMapping, TransformedStringTypeKind, PrimitiveStringTypeKind } from ".."; +import { type StringTypeMapping, type TransformedStringTypeKind, type PrimitiveStringTypeKind } from ".."; export const javaOptions = { useList: new EnumOption( @@ -32,9 +37,9 @@ export const javaOptions = { "Use T[] or List", [ ["array", false], - ["list", true] + ["list", true], ], - "array" + "array", ), justTypes: new BooleanOption("just-types", "Plain types only", false), dateTimeProvider: new EnumOption( @@ -42,23 +47,23 @@ export const javaOptions = { "Date time provider type", [ ["java8", "java8"], - ["legacy", "legacy"] + ["legacy", "legacy"], ], - "java8" + "java8", ), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), // FIXME: Do this via a configurable named eventually. packageName: new StringOption("package", "Generated package name", "NAME", "io.quicktype"), lombok: new BooleanOption("lombok", "Use lombok", false, "primary"), - lombokCopyAnnotations: new BooleanOption("lombok-copy-annotations", "Copy accessor annotations", true, "secondary") + lombokCopyAnnotations: new BooleanOption("lombok-copy-annotations", "Copy accessor annotations", true, "secondary"), }; export class JavaTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Java", ["java"], "java"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ javaOptions.useList, javaOptions.justTypes, @@ -66,23 +71,24 @@ export class JavaTargetLanguage extends TargetLanguage { javaOptions.acronymStyle, javaOptions.packageName, javaOptions.lombok, - javaOptions.lombokCopyAnnotations + javaOptions.lombokCopyAnnotations, ]; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): JavaRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): JavaRenderer { const options = getOptionValues(javaOptions, untypedOptionValues); if (options.justTypes) { return new JavaRenderer(this, renderContext, options); } + return new JacksonRenderer(this, renderContext, options); } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date"); mapping.set("time", "time"); @@ -159,27 +165,27 @@ const javaKeywords = [ "while", "null", "false", - "true" + "true", ]; export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); -function isStartCharacter(codePoint: number): boolean { +function isStartCharacter (codePoint: number): boolean { if (codePoint === 0x5f) return true; // underscore return isAscii(codePoint) && isLetter(codePoint); } -function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); +function isPartCharacter (codePoint: number): boolean { + return isStartCharacter(codePoint) || isAscii(codePoint) && isDigit(codePoint); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); -export function javaNameStyle( +export function javaNameStyle ( startWithUpper: boolean, upperUnderscore: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle + acronymsStyle: (s: string) => string = allUpperWordStyle, ): string { const words = splitIntoWords(original); return combineWords( @@ -190,43 +196,53 @@ export function javaNameStyle( upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, upperUnderscore ? "_" : "", - isStartCharacter + isStartCharacter, ); } abstract class JavaDateTimeProvider { - constructor( + constructor ( protected readonly _renderer: JavaRenderer, - protected readonly _className: string + protected readonly _className: string, ) {} + abstract keywords: string[]; abstract dateTimeImports: string[]; + abstract dateImports: string[]; + abstract timeImports: string[]; + abstract converterImports: string[]; abstract dateTimeType: string; + abstract dateType: string; + abstract timeType: string; abstract dateTimeJacksonAnnotations: string[]; + abstract dateJacksonAnnotations: string[]; + abstract timeJacksonAnnotations: string[]; - abstract emitDateTimeConverters(): void; + abstract emitDateTimeConverters (): void; public shouldEmitDateTimeConverter = true; + public shouldEmitTimeConverter = true; + public shouldEmitDateConverter = true; - abstract convertStringToDateTime(variable: Sourcelike): Sourcelike; - abstract convertStringToTime(variable: Sourcelike): Sourcelike; - abstract convertStringToDate(variable: Sourcelike): Sourcelike; + abstract convertStringToDateTime (variable: Sourcelike): Sourcelike; + abstract convertStringToTime (variable: Sourcelike): Sourcelike; + abstract convertStringToDate (variable: Sourcelike): Sourcelike; - abstract convertDateTimeToString(variable: Sourcelike): Sourcelike; - abstract convertTimeToString(variable: Sourcelike): Sourcelike; - abstract convertDateToString(variable: Sourcelike): Sourcelike; + abstract convertDateTimeToString (variable: Sourcelike): Sourcelike; + abstract convertTimeToString (variable: Sourcelike): Sourcelike; + abstract convertDateToString (variable: Sourcelike): Sourcelike; } class Java8DateTimeProvider extends JavaDateTimeProvider { @@ -238,12 +254,15 @@ class Java8DateTimeProvider extends JavaDateTimeProvider { "ZonedDateTime", "DateTimeFormatter", "DateTimeFormatterBuilder", - "ChronoField" + "ChronoField", ]; dateTimeImports: string[] = ["java.time.OffsetDateTime"]; + dateImports: string[] = ["java.time.LocalDate"]; + timeImports: string[] = ["java.time.OffsetTime"]; + converterImports: string[] = [ "java.time.LocalDate", "java.time.OffsetDateTime", @@ -252,44 +271,48 @@ class Java8DateTimeProvider extends JavaDateTimeProvider { "java.time.ZonedDateTime", "java.time.format.DateTimeFormatter", "java.time.format.DateTimeFormatterBuilder", - "java.time.temporal.ChronoField" + "java.time.temporal.ChronoField", ]; dateTimeType = "OffsetDateTime"; + dateType = "LocalDate"; + timeType = "OffsetTime"; dateTimeJacksonAnnotations: string[] = []; + dateJacksonAnnotations: string[] = []; + timeJacksonAnnotations: string[] = []; - emitDateTimeConverters(): void { + emitDateTimeConverters (): void { this._renderer.ensureBlankLine(); this._renderer.emitLine( - "private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()" + "private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()", ); this._renderer.indent(() => this._renderer.indent(() => { this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_DATE_TIME)"); this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)"); this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_INSTANT)"); - this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SX"))'); - this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX"))'); - this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))'); + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.SX\"))"); + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ssX\"))"); + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\"))"); this._renderer.emitLine(".toFormatter()"); this._renderer.emitLine(".withZone(ZoneOffset.UTC);"); - }) + }), ); this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static OffsetDateTime parseDateTimeString(String str)", () => { this._renderer.emitLine( - "return ZonedDateTime.from(Converter.DATE_TIME_FORMATTER.parse(str)).toOffsetDateTime();" + "return ZonedDateTime.from(Converter.DATE_TIME_FORMATTER.parse(str)).toOffsetDateTime();", ); }); this._renderer.ensureBlankLine(); this._renderer.emitLine( - "private static final DateTimeFormatter TIME_FORMATTER = new DateTimeFormatterBuilder()" + "private static final DateTimeFormatter TIME_FORMATTER = new DateTimeFormatterBuilder()", ); this._renderer.indent(() => this._renderer.indent(() => { @@ -300,37 +323,37 @@ class Java8DateTimeProvider extends JavaDateTimeProvider { this._renderer.emitLine(".parseDefaulting(ChronoField.DAY_OF_MONTH, 1)"); this._renderer.emitLine(".toFormatter()"); this._renderer.emitLine(".withZone(ZoneOffset.UTC);"); - }) + }), ); this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static OffsetTime parseTimeString(String str)", () => { this._renderer.emitLine( - "return ZonedDateTime.from(Converter.TIME_FORMATTER.parse(str)).toOffsetDateTime().toOffsetTime();" + "return ZonedDateTime.from(Converter.TIME_FORMATTER.parse(str)).toOffsetDateTime().toOffsetTime();", ); }); } - convertStringToDateTime(variable: Sourcelike): Sourcelike { + convertStringToDateTime (variable: Sourcelike): Sourcelike { return [this._className, ".parseDateTimeString(", variable, ")"]; } - convertStringToTime(variable: Sourcelike): Sourcelike { + convertStringToTime (variable: Sourcelike): Sourcelike { return [this._className, ".parseTimeString(", variable, ")"]; } - convertStringToDate(variable: Sourcelike): Sourcelike { + convertStringToDate (variable: Sourcelike): Sourcelike { return ["LocalDate.parse(", variable, ")"]; } - convertDateTimeToString(variable: Sourcelike): Sourcelike { + convertDateTimeToString (variable: Sourcelike): Sourcelike { return [variable, ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)"]; } - convertTimeToString(variable: Sourcelike): Sourcelike { + convertTimeToString (variable: Sourcelike): Sourcelike { return [variable, ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_TIME)"]; } - convertDateToString(variable: Sourcelike): Sourcelike { + convertDateToString (variable: Sourcelike): Sourcelike { return [variable, ".format(java.time.format.DateTimeFormatter.ISO_DATE)"]; } } @@ -339,19 +362,26 @@ class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { keywords = ["SimpleDateFormat", "Date"]; dateTimeImports: string[] = ["java.util.Date"]; + dateImports: string[] = ["java.util.Date"]; + timeImports: string[] = ["java.util.Date"]; + converterImports: string[] = ["java.util.Date", "java.text.SimpleDateFormat"]; dateTimeType = "Date"; + dateType = "Date"; + timeType = "Date"; - dateTimeJacksonAnnotations: string[] = ['@JsonFormat(pattern = "yyyy-MM-dd\'T\'HH:mm:ssX", timezone = "UTC")']; - dateJacksonAnnotations: string[] = ['@JsonFormat(pattern = "yyyy-MM-dd")']; - timeJacksonAnnotations: string[] = ['@JsonFormat(pattern = "HH:mm:ssX", timezone = "UTC")']; + dateTimeJacksonAnnotations: string[] = ["@JsonFormat(pattern = \"yyyy-MM-dd'T'HH:mm:ssX\", timezone = \"UTC\")"]; - emitDateTimeConverters(): void { + dateJacksonAnnotations: string[] = ["@JsonFormat(pattern = \"yyyy-MM-dd\")"]; + + timeJacksonAnnotations: string[] = ["@JsonFormat(pattern = \"HH:mm:ssX\", timezone = \"UTC\")"]; + + emitDateTimeConverters (): void { this._renderer.ensureBlankLine(); this._renderer.emitLine("private static final String[] DATE_TIME_FORMATS = {"); this._renderer.indent(() => @@ -360,16 +390,16 @@ class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ss.S\","); this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ssX\","); this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ss\","); - this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss.SX",'); - this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss.S",'); - this._renderer.emitLine('"yyyy-MM-dd HH:mm:ssX",'); - this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss",'); - this._renderer.emitLine('"HH:mm:ss.SZ",'); - this._renderer.emitLine('"HH:mm:ss.S",'); - this._renderer.emitLine('"HH:mm:ssZ",'); - this._renderer.emitLine('"HH:mm:ss",'); - this._renderer.emitLine('"yyyy-MM-dd",'); - }) + this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ss.SX\","); + this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ss.S\","); + this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ssX\","); + this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ss\","); + this._renderer.emitLine("\"HH:mm:ss.SZ\","); + this._renderer.emitLine("\"HH:mm:ss.S\","); + this._renderer.emitLine("\"HH:mm:ssZ\","); + this._renderer.emitLine("\"HH:mm:ss\","); + this._renderer.emitLine("\"yyyy-MM-dd\","); + }), ); this._renderer.emitLine("};"); this._renderer.ensureBlankLine(); @@ -389,55 +419,61 @@ class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static String serializeDate(Date datetime)", () => { - this._renderer.emitLine('return new SimpleDateFormat("yyyy-MM-dd").format(datetime);'); + this._renderer.emitLine("return new SimpleDateFormat(\"yyyy-MM-dd\").format(datetime);"); }); this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static String serializeTime(Date datetime)", () => { - this._renderer.emitLine('return new SimpleDateFormat("hh:mm:ssZ").format(datetime);'); + this._renderer.emitLine("return new SimpleDateFormat(\"hh:mm:ssZ\").format(datetime);"); }); } shouldEmitTimeConverter = false; + shouldEmitDateConverter = false; - convertStringToDateTime(variable: Sourcelike): Sourcelike { + convertStringToDateTime (variable: Sourcelike): Sourcelike { return [this._className, ".parseAllDateTimeString(", variable, ")"]; } - convertStringToTime(variable: Sourcelike): Sourcelike { + convertStringToTime (variable: Sourcelike): Sourcelike { return [this._className, ".parseAllDateTimeString(", variable, ")"]; } - convertStringToDate(variable: Sourcelike): Sourcelike { + convertStringToDate (variable: Sourcelike): Sourcelike { return [this._className, ".parseAllDateTimeString(", variable, ")"]; } - convertDateTimeToString(variable: Sourcelike): Sourcelike { + convertDateTimeToString (variable: Sourcelike): Sourcelike { return [this._className, ".serializeDateTime(", variable, ")"]; } - convertTimeToString(variable: Sourcelike): Sourcelike { + convertTimeToString (variable: Sourcelike): Sourcelike { return [this._className, ".serializeTime(", variable, ")"]; } - convertDateToString(variable: Sourcelike): Sourcelike { + convertDateToString (variable: Sourcelike): Sourcelike { return [this._className, ".serializeDate(", variable, ")"]; } } export class JavaRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; + private readonly _gettersAndSettersForPropertyName = new Map(); + private _haveEmittedLeadingComments = false; + protected readonly _dateTimeProvider: JavaDateTimeProvider; + protected readonly _converterClassname: string = "Converter"; + protected readonly _converterKeywords: string[] = []; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues + protected readonly _options: OptionValues, ) { super(targetLanguage, renderContext); @@ -452,125 +488,127 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { const keywords = [ ...javaKeywords, ...this._converterKeywords, this._converterClassname, - ...this._dateTimeProvider.keywords + ...this._dateTimeProvider.keywords, ]; return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return this.getNameStyling("typeNamingFunction"); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return this.getNameStyling("enumCaseNamingFunction"); } - protected unionNeedsName(u: UnionType): boolean { + protected unionNeedsName (u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { // If the top-level type doesn't contain any classes or unions // we have to define a class just for the `FromJson` method, in // emitFromJsonForTopLevel. return directlyReachableSingleNamedType(type); } - protected makeNamesForPropertyGetterAndSetter( + protected makeNamesForPropertyGetterAndSetter ( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name + name: Name, ): [Name, Name] { const getterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `get_${lookup(name)}` + lookup => `get_${lookup(name)}`, ); const setterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `set_${lookup(name)}` + lookup => `set_${lookup(name)}`, ); return [getterName, setterName]; } - protected makePropertyDependencyNames( + protected makePropertyDependencyNames ( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return getterAndSetterNames; } - private getNameStyling(convention: string): Namer { - const styling: { [key: string]: Namer } = { + private getNameStyling (convention: string): Namer { + const styling: { [key: string]: Namer, } = { typeNamingFunction: funPrefixNamer("types", n => - javaNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)) + javaNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)), ), propertyNamingFunction: funPrefixNamer("properties", n => - javaNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)) + javaNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)), ), enumCaseNamingFunction: funPrefixNamer("enum-cases", n => - javaNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)) - ) + javaNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)), + ), }; return styling[convention]; } - protected fieldOrMethodName(methodName: string, topLevelName: Name): Sourcelike { + protected fieldOrMethodName (methodName: string, topLevelName: Name): Sourcelike { if (this.topLevels.size === 1) { return methodName; } + return [topLevelName, capitalize(methodName)]; } - protected methodName(prefix: string, suffix: string, topLevelName: Name): Sourcelike { + protected methodName (prefix: string, suffix: string, topLevelName: Name): Sourcelike { if (this.topLevels.size === 1) { return [prefix, suffix]; } + return [prefix, topLevelName, suffix]; } - protected decoderName(topLevelName: Name): Sourcelike { + protected decoderName (topLevelName: Name): Sourcelike { return this.fieldOrMethodName("fromJsonString", topLevelName); } - protected encoderName(topLevelName: Name): Sourcelike { + protected encoderName (topLevelName: Name): Sourcelike { return this.fieldOrMethodName("toJsonString", topLevelName); } - protected readerGetterName(topLevelName: Name): Sourcelike { + protected readerGetterName (topLevelName: Name): Sourcelike { return this.methodName("get", "ObjectReader", topLevelName); } - protected writerGetterName(topLevelName: Name): Sourcelike { + protected writerGetterName (topLevelName: Name): Sourcelike { return this.methodName("get", "ObjectWriter", topLevelName); } - protected startFile(basename: Sourcelike): void { + protected startFile (basename: Sourcelike): void { assert(this._currentFilename === undefined, "Previous file wasn't finished"); // FIXME: The filenames should actually be Sourcelikes, too this._currentFilename = `${this.sourcelikeToString(basename)}.java`; @@ -583,12 +621,12 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected finishFile(): void { + protected finishFile (): void { super.finishFile(defined(this._currentFilename)); this._currentFilename = undefined; } - protected emitPackageAndImports(imports: string[]): void { + protected emitPackageAndImports (imports: string[]): void { this.emitLine("package ", this._options.packageName, ";"); this.ensureBlankLine(); for (const pkg of imports) { @@ -596,23 +634,23 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected emitFileHeader(fileName: Sourcelike, imports: string[]): void { + protected emitFileHeader (fileName: Sourcelike, imports: string[]): void { this.startFile(fileName); this.emitPackageAndImports(imports); this.ensureBlankLine(); } - public emitDescriptionBlock(lines: Sourcelike[]): void { + public emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - public emitBlock(line: Sourcelike, f: () => void): void { + public emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - public emitTryCatch(main: () => void, handler: () => void, exception = "Exception") { + public emitTryCatch (main: () => void, handler: () => void, exception = "Exception") { this.emitLine("try {"); this.indent(main); this.emitLine("} catch (", exception, " ex) {"); @@ -620,18 +658,18 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitLine("}"); } - public emitIgnoredTryCatchBlock(f: () => void) { + public emitIgnoredTryCatchBlock (f: () => void) { this.emitTryCatch(f, () => this.emitLine("// Ignored")); } - protected javaType(reference: boolean, t: Type, withIssues = false): Sourcelike { + protected javaType (reference: boolean, t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "Object"), _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, "Object"), - _boolType => (reference ? "Boolean" : "boolean"), - _integerType => (reference ? "Long" : "long"), - _doubleType => (reference ? "Double" : "double"), + _boolType => reference ? "Boolean" : "boolean", + _integerType => reference ? "Long" : "long", + _doubleType => reference ? "Double" : "double", _stringType => "String", arrayType => { if (this._options.useList) { @@ -652,21 +690,25 @@ export class JavaRenderer extends ConvenienceRenderer { if (transformedStringType.kind === "time") { return this._dateTimeProvider.timeType; } + if (transformedStringType.kind === "date") { return this._dateTimeProvider.dateType; } + if (transformedStringType.kind === "date-time") { return this._dateTimeProvider.dateTimeType; } + if (transformedStringType.kind === "uuid") { return "UUID"; } + return "String"; - } + }, ); } - protected javaImport(t: Type): string[] { + protected javaImport (t: Type): string[] { return matchType( t, _anyType => [], @@ -694,21 +736,25 @@ export class JavaRenderer extends ConvenienceRenderer { if (transformedStringType.kind === "time") { return this._dateTimeProvider.timeImports; } + if (transformedStringType.kind === "date") { return this._dateTimeProvider.dateImports; } + if (transformedStringType.kind === "date-time") { return this._dateTimeProvider.dateTimeImports; } + if (transformedStringType.kind === "uuid") { return ["java.util.UUID"]; } + return []; - } + }, ); } - protected javaTypeWithoutGenerics(reference: boolean, t: Type): Sourcelike { + protected javaTypeWithoutGenerics (reference: boolean, t: Type): Sourcelike { if (t instanceof ArrayType) { if (this._options.useList) { return ["List"]; @@ -726,37 +772,40 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected emitClassAttributes(_c: ClassType, _className: Name): void { + protected emitClassAttributes (_c: ClassType, _className: Name): void { if (this._options.lombok) { this.emitLine("@lombok.Data"); } } - protected annotationsForAccessor( + protected annotationsForAccessor ( _c: ClassType, _className: Name, _propertyName: Name, _jsonName: string, _p: ClassProperty, - _isSetter: boolean + _isSetter: boolean, ): string[] { return []; } - protected importsForType(t: ClassType | UnionType | EnumType): string[] { + protected importsForType (t: ClassType | UnionType | EnumType): string[] { if (t instanceof ClassType) { return []; } + if (t instanceof UnionType) { return ["java.io.IOException"]; } + if (t instanceof EnumType) { return ["java.io.IOException"]; } + return assertNever(t); } - protected importsForClass(c: ClassType): string[] { + protected importsForClass (c: ClassType): string[] { const imports: string[] = []; this.forEachClassProperty(c, "none", (_name, _jsonName, p) => { this.javaImport(p.type).forEach(imp => imports.push(imp)); @@ -765,7 +814,7 @@ export class JavaRenderer extends ConvenienceRenderer { return [...new Set(imports)]; } - protected importsForUnionMembers(u: UnionType): string[] { + protected importsForUnionMembers (u: UnionType): string[] { const imports: string[] = []; const [, nonNulls] = removeNullFromUnion(u); this.forEachUnionMember(u, nonNulls, "none", null, (_fieldName, t) => { @@ -775,7 +824,7 @@ export class JavaRenderer extends ConvenienceRenderer { return [...new Set(imports)]; } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition (c: ClassType, className: Name): void { let imports = [...this.importsForType(c), ...this.importsForClass(c)]; this.emitFileHeader(className, imports); @@ -789,10 +838,12 @@ export class JavaRenderer extends ConvenienceRenderer { if (getter.length !== 0) { this.emitLine("@lombok.Getter(onMethod_ = {" + getter.join(", ") + "})"); } + if (setter.length !== 0) { this.emitLine("@lombok.Setter(onMethod_ = {" + setter.join(", ") + "})"); } } + this.emitLine("private ", this.javaType(false, p.type, true), " ", name, ";"); }); if (!this._options.lombok) { @@ -801,11 +852,11 @@ export class JavaRenderer extends ConvenienceRenderer { const [getterName, setterName] = defined(this._gettersAndSettersForPropertyName.get(name)); const rendered = this.javaType(false, p.type); this.annotationsForAccessor(c, className, name, jsonName, p, false).forEach(annotation => - this.emitLine(annotation) + this.emitLine(annotation), ); this.emitLine("public ", rendered, " ", getterName, "() { return ", name, "; }"); this.annotationsForAccessor(c, className, name, jsonName, p, true).forEach(annotation => - this.emitLine(annotation) + this.emitLine(annotation), ); this.emitLine("public void ", setterName, "(", rendered, " value) { this.", name, " = value; }"); }); @@ -814,22 +865,22 @@ export class JavaRenderer extends ConvenienceRenderer { this.finishFile(); } - protected unionField(u: UnionType, t: Type, withIssues = false): { fieldType: Sourcelike; fieldName: Sourcelike } { + protected unionField (u: UnionType, t: Type, withIssues = false): { fieldName: Sourcelike, fieldType: Sourcelike, } { const fieldType = this.javaType(true, t, withIssues); // FIXME: "Value" should be part of the name. const fieldName = [this.nameForUnionMember(u, t), "Value"]; return { fieldType, fieldName }; } - protected emitUnionAttributes(_u: UnionType, _unionName: Name): void { + protected emitUnionAttributes (_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionSerializer(_u: UnionType, _unionName: Name): void { + protected emitUnionSerializer (_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionDefinition(u: UnionType, unionName: Name): void { + protected emitUnionDefinition (u: UnionType, unionName: Name): void { const imports = [...this.importsForType(u), ...this.importsForUnionMembers(u)]; this.emitFileHeader(unionName, imports); @@ -842,20 +893,21 @@ export class JavaRenderer extends ConvenienceRenderer { const { fieldType, fieldName } = this.unionField(u, t, true); this.emitLine("public ", fieldType, " ", fieldName, ";"); } + this.emitUnionSerializer(u, unionName); }); this.finishFile(); } - protected emitEnumSerializationAttributes(_e: EnumType) { + protected emitEnumSerializationAttributes (_e: EnumType) { // Empty } - protected emitEnumDeserializationAttributes(_e: EnumType) { + protected emitEnumDeserializationAttributes (_e: EnumType) { // Empty } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitFileHeader(enumName, this.importsForType(e)); this.emitDescription(this.descriptionForType(e)); const caseNames: Sourcelike[] = []; @@ -873,7 +925,7 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitLine("switch (this) {"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("case ", name, ': return "', stringEscape(jsonName), '";'); + this.emitLine("case ", name, ": return \"", stringEscape(jsonName), "\";"); }); }); this.emitLine("}"); @@ -884,29 +936,29 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitEnumDeserializationAttributes(e); this.emitBlock(["public static ", enumName, " forValue(String value) throws IOException"], () => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine('if (value.equals("', stringEscape(jsonName), '")) return ', name, ";"); + this.emitLine("if (value.equals(\"", stringEscape(jsonName), "\")) return ", name, ";"); }); - this.emitLine('throw new IOException("Cannot deserialize ', enumName, '");'); + this.emitLine("throw new IOException(\"Cannot deserialize ", enumName, "\");"); }); }); this.finishFile(); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.forEachNamedType( "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n) + (u, n) => this.emitUnionDefinition(u, n), ); } } export class JacksonRenderer extends JavaRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - options: OptionValues + options: OptionValues, ) { super(targetLanguage, renderContext, options); } @@ -920,27 +972,27 @@ export class JacksonRenderer extends JavaRenderer { "JsonParser", "JsonProcessingException", "DeserializationContext", - "SerializerProvider" + "SerializerProvider", ]; - protected emitClassAttributes(c: ClassType, _className: Name): void { + protected emitClassAttributes (c: ClassType, _className: Name): void { if (c.getProperties().size === 0) this.emitLine("@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.NONE)"); super.emitClassAttributes(c, _className); } - protected annotationsForAccessor( + protected annotationsForAccessor ( _c: ClassType, _className: Name, _propertyName: Name, jsonName: string, p: ClassProperty, - _isSetter: boolean + _isSetter: boolean, ): string[] { const superAnnotations = super.annotationsForAccessor(_c, _className, _propertyName, jsonName, p, _isSetter); - const annotations: string[] = ['@JsonProperty("' + stringEscape(jsonName) + '")']; + const annotations: string[] = ["@JsonProperty(\"" + stringEscape(jsonName) + "\")"]; switch (p.type.kind) { case "date-time": @@ -959,39 +1011,43 @@ export class JacksonRenderer extends JavaRenderer { return [...superAnnotations, ...annotations]; } - protected importsForType(t: ClassType | UnionType | EnumType): string[] { + protected importsForType (t: ClassType | UnionType | EnumType): string[] { if (t instanceof ClassType) { const imports = super.importsForType(t); imports.push("com.fasterxml.jackson.annotation.*"); return imports; } + if (t instanceof UnionType) { const imports = super.importsForType(t); imports.push( "java.io.IOException", "com.fasterxml.jackson.core.*", "com.fasterxml.jackson.databind.*", - "com.fasterxml.jackson.databind.annotation.*" + "com.fasterxml.jackson.databind.annotation.*", ); if (this._options.useList) { imports.push("com.fasterxml.jackson.core.type.*"); } + return imports; } + if (t instanceof EnumType) { const imports = super.importsForType(t); imports.push("com.fasterxml.jackson.annotation.*"); return imports; } + return assertNever(t); } - protected emitUnionAttributes(_u: UnionType, unionName: Name): void { + protected emitUnionAttributes (_u: UnionType, unionName: Name): void { this.emitLine("@JsonDeserialize(using = ", unionName, ".Deserializer.class)"); this.emitLine("@JsonSerialize(using = ", unionName, ".Serializer.class)"); } - protected emitUnionSerializer(u: UnionType, unionName: Name): void { + protected emitUnionSerializer (u: UnionType, unionName: Name): void { const stringBasedObjects: TypeKind[] = ["uuid", "time", "date", "date-time"]; const tokenCase = (tokenType: string): void => { @@ -1008,7 +1064,7 @@ export class JacksonRenderer extends JavaRenderer { const emitDeserializerCodeForStringObjects = ( fieldName: Sourcelike, kind: TypeKind, - parseFrom: string + parseFrom: string, ): void => { switch (kind) { case "date": @@ -1017,7 +1073,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = ", this._dateTimeProvider.convertStringToDate(parseFrom), - ";" + ";", ); break; @@ -1027,7 +1083,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = ", this._dateTimeProvider.convertStringToTime(parseFrom), - ";" + ";", ); break; @@ -1037,7 +1093,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = ", this._dateTimeProvider.convertStringToDateTime(parseFrom), - ";" + ";", ); break; case "uuid": @@ -1058,7 +1114,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = jsonParser.readValueAs(new TypeReference<", rendered, - ">() {});" + ">() {});", ); } else if (stringBasedObjects.some(stringBasedTypeKind => t.kind === stringBasedTypeKind)) { emitDeserializerCodeForStringObjects(fieldName, t.kind, variableFieldName); @@ -1080,6 +1136,7 @@ export class JacksonRenderer extends JavaRenderer { for (const tokenType of tokenTypes) { tokenCase(tokenType); } + this.indent(() => { emitDeserializeType(t); this.emitLine("break;"); @@ -1124,6 +1181,7 @@ export class JacksonRenderer extends JavaRenderer { if (stringType !== undefined) { emitDeserializeType(stringType, fromVariable); } + this.emitLine("break;"); }); }); @@ -1142,6 +1200,7 @@ export class JacksonRenderer extends JavaRenderer { this.emitLine("break;"); }); } + if (doubleType !== undefined) { tokenCase("VALUE_NUMBER_FLOAT"); this.indent(() => { @@ -1176,6 +1235,7 @@ export class JacksonRenderer extends JavaRenderer { } else { this.emitLine("jsonGenerator.writeObject(obj.", fieldName, ");"); } + this.emitLine("return;"); }); }; @@ -1189,7 +1249,7 @@ export class JacksonRenderer extends JavaRenderer { [ "public ", unionName, - " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException" + " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException", ], () => { this.emitLine(unionName, " value = new ", unionName, "();"); @@ -1202,11 +1262,11 @@ export class JacksonRenderer extends JavaRenderer { emitDeserializer(["START_OBJECT"], "class"); emitDeserializer(["START_OBJECT"], "map"); this.indent(() => - this.emitLine('default: throw new IOException("Cannot deserialize ', unionName, '");') + this.emitLine("default: throw new IOException(\"Cannot deserialize ", unionName, "\");"), ); this.emitLine("}"); this.emitLine("return value;"); - } + }, ); }); this.ensureBlankLine(); @@ -1216,31 +1276,32 @@ export class JacksonRenderer extends JavaRenderer { [ "public void serialize(", unionName, - " obj, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException" + " obj, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException", ], () => { for (const t of nonNulls) { emitSerializeType(t); } + if (maybeNull !== null) { this.emitLine("jsonGenerator.writeNull();"); } else { - this.emitLine('throw new IOException("', unionName, ' must not be null");'); + this.emitLine("throw new IOException(\"", unionName, " must not be null\");"); } - } + }, ); }); } - protected emitEnumSerializationAttributes(_e: EnumType) { + protected emitEnumSerializationAttributes (_e: EnumType) { this.emitLine("@JsonValue"); } - protected emitEnumDeserializationAttributes(_e: EnumType) { + protected emitEnumDeserializationAttributes (_e: EnumType) { this.emitLine("@JsonCreator"); } - protected emitOffsetDateTimeConverterModule(): void { + protected emitOffsetDateTimeConverterModule (): void { this.emitLine("SimpleModule module = new SimpleModule();"); if (this._dateTimeProvider.shouldEmitDateTimeConverter) { @@ -1249,7 +1310,7 @@ export class JacksonRenderer extends JavaRenderer { this._dateTimeProvider.dateTimeType, ".class, new JsonDeserializer<", this._dateTimeProvider.dateTimeType, - ">() {" + ">() {", ); this.indent(() => { this.emitLine("@Override"); @@ -1258,12 +1319,12 @@ export class JacksonRenderer extends JavaRenderer { "public ", this._dateTimeProvider.dateTimeType, " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", - "throws IOException, JsonProcessingException" + "throws IOException, JsonProcessingException", ], () => { this.emitLine("String value = jsonParser.getText();"); this.emitLine("return ", this._dateTimeProvider.convertStringToDateTime("value"), ";"); - } + }, ); }); this.emitLine("});"); @@ -1275,7 +1336,7 @@ export class JacksonRenderer extends JavaRenderer { this._dateTimeProvider.timeType, ".class, new JsonDeserializer<", this._dateTimeProvider.timeType, - ">() {" + ">() {", ); this.indent(() => { this.emitLine("@Override"); @@ -1284,12 +1345,12 @@ export class JacksonRenderer extends JavaRenderer { "public ", this._dateTimeProvider.timeType, " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", - "throws IOException, JsonProcessingException" + "throws IOException, JsonProcessingException", ], () => { this.emitLine("String value = jsonParser.getText();"); this.emitLine("return ", this._dateTimeProvider.convertStringToTime("value"), ";"); - } + }, ); }); this.emitLine("});"); @@ -1301,7 +1362,7 @@ export class JacksonRenderer extends JavaRenderer { this._dateTimeProvider.dateType, ".class, new JsonDeserializer<", this._dateTimeProvider.dateType, - ">() {" + ">() {", ); this.indent(() => { this.emitLine("@Override"); @@ -1310,12 +1371,12 @@ export class JacksonRenderer extends JavaRenderer { "public ", this._dateTimeProvider.dateType, " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", - "throws IOException, JsonProcessingException" + "throws IOException, JsonProcessingException", ], () => { this.emitLine("String value = jsonParser.getText();"); this.emitLine("return ", this._dateTimeProvider.convertStringToDate("value"), ";"); - } + }, ); }); this.emitLine("});"); @@ -1324,7 +1385,7 @@ export class JacksonRenderer extends JavaRenderer { this.emitLine("mapper.registerModule(module);"); } - protected emitConverterClass(): void { + protected emitConverterClass (): void { this.startFile(this._converterClassname); this.emitCommentLines([ "To use this code, add the following Maven dependency to your project:", @@ -1336,7 +1397,7 @@ export class JacksonRenderer extends JavaRenderer { : "", "", "Import this package:", - "" + "", ]); this.emitLine("// import ", this._options.packageName, ".Converter;"); this.emitMultiline(`// @@ -1348,7 +1409,7 @@ export class JacksonRenderer extends JavaRenderer { this.javaType(false, t), " data = Converter.", this.decoderName(name), - "(jsonString);" + "(jsonString);", ); }); this.ensureBlankLine(); @@ -1358,7 +1419,7 @@ export class JacksonRenderer extends JavaRenderer { "com.fasterxml.jackson.databind.module.SimpleModule", "com.fasterxml.jackson.core.JsonParser", "com.fasterxml.jackson.core.JsonProcessingException", - "java.util.*" + "java.util.*", ].concat(this._dateTimeProvider.converterImports); this.emitPackageAndImports(imports); this.ensureBlankLine(); @@ -1375,11 +1436,11 @@ export class JacksonRenderer extends JavaRenderer { topLevelTypeRendered, " ", this.decoderName(topLevelName), - "(String json) throws IOException" + "(String json) throws IOException", ], () => { this.emitLine("return ", this.readerGetterName(topLevelName), "().readValue(json);"); - } + }, ); this.ensureBlankLine(); this.emitBlock( @@ -1388,11 +1449,11 @@ export class JacksonRenderer extends JavaRenderer { this.encoderName(topLevelName), "(", topLevelTypeRendered, - " obj) throws JsonProcessingException" + " obj) throws JsonProcessingException", ], () => { this.emitLine("return ", this.writerGetterName(topLevelName), "().writeValueAsString(obj);"); - } + }, ); }); this.forEachTopLevel("leading-and-interposing", (topLevelType, topLevelName) => { @@ -1412,7 +1473,7 @@ export class JacksonRenderer extends JavaRenderer { this.emitOffsetDateTimeConverterModule(); this.emitLine(readerName, " = mapper.readerFor(", renderedForClass, ".class);"); this.emitLine(writerName, " = mapper.writerFor(", renderedForClass, ".class);"); - } + }, ); this.ensureBlankLine(); this.emitBlock(["private static ObjectReader ", this.readerGetterName(topLevelName), "()"], () => { @@ -1421,7 +1482,7 @@ export class JacksonRenderer extends JavaRenderer { readerName, " == null) ", this.methodName("instantiate", "Mapper", topLevelName), - "();" + "();", ); this.emitLine("return ", readerName, ";"); }); @@ -1432,7 +1493,7 @@ export class JacksonRenderer extends JavaRenderer { writerName, " == null) ", this.methodName("instantiate", "Mapper", topLevelName), - "();" + "();", ); this.emitLine("return ", writerName, ";"); }); @@ -1441,7 +1502,7 @@ export class JacksonRenderer extends JavaRenderer { this.finishFile(); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.emitConverterClass(); super.emitSourceStructure(); } diff --git a/packages/quicktype-core/src/language/JavaScript.ts b/packages/quicktype-core/src/language/JavaScript.ts index e8e3db9a2..1936de7b2 100644 --- a/packages/quicktype-core/src/language/JavaScript.ts +++ b/packages/quicktype-core/src/language/JavaScript.ts @@ -1,12 +1,12 @@ import { arrayIntercalate } from "collection-utils"; import { - TransformedStringTypeKind, - PrimitiveStringTypeKind, - Type, - ClassProperty, - ClassType, - ObjectType + type TransformedStringTypeKind, + type PrimitiveStringTypeKind, + type Type, + type ClassProperty, + type ClassType, + type ObjectType, } from "../Type"; import { matchType, directlyReachableSingleNamedType } from "../TypeUtils"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; @@ -20,17 +20,20 @@ import { combineWords, firstUpperWordStyle, camelCase, - allLowerWordStyle + allLowerWordStyle, } from "../support/Strings"; import { panic } from "../support/Support"; -import { Sourcelike, modifySource } from "../Source"; -import { Namer, Name, funPrefixNamer } from "../Naming"; +import { type Sourcelike} from "../Source"; +import { modifySource } from "../Source"; +import { type Namer, type Name} from "../Naming"; +import { funPrefixNamer } from "../Naming"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { TargetLanguage } from "../TargetLanguage"; -import { StringTypeMapping } from "../TypeBuilder"; -import { BooleanOption, Option, OptionValues, getOptionValues, EnumOption } from "../RendererOptions"; -import { RenderContext } from "../Renderer"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { BooleanOption, getOptionValues, EnumOption } from "../RendererOptions"; +import { type RenderContext } from "../Renderer"; import { isES3IdentifierPart, isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; export const javaScriptOptions = { @@ -40,7 +43,7 @@ export const javaScriptOptions = { "runtime-typecheck-ignore-unknown-properties", "Ignore unknown properties when verifying at runtime", false, - "secondary" + "secondary", ), converters: convertersOption(), rawType: new EnumOption<"json" | "any">( @@ -48,39 +51,39 @@ export const javaScriptOptions = { "Type of raw input (json by default)", [ ["json", "json"], - ["any", "any"] + ["any", "any"], ], "json", - "secondary" - ) + "secondary", + ), }; -export type JavaScriptTypeAnnotations = { +export interface JavaScriptTypeAnnotations { any: string; anyArray: string; anyMap: string; - string: string; - stringArray: string; boolean: string; never: string; -}; + string: string; + stringArray: string; +} export class JavaScriptTargetLanguage extends TargetLanguage { - constructor(displayName = "JavaScript", names: string[] = ["javascript", "js", "jsx"], extension = "js") { + constructor (displayName = "JavaScript", names: string[] = ["javascript", "js", "jsx"], extension = "js") { super(displayName, names, extension); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ javaScriptOptions.runtimeTypecheck, javaScriptOptions.runtimeTypecheckIgnoreUnknownProperties, javaScriptOptions.acronymStyle, javaScriptOptions.converters, - javaScriptOptions.rawType + javaScriptOptions.rawType, ]; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); @@ -88,17 +91,17 @@ export class JavaScriptTargetLanguage extends TargetLanguage { return mapping; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsFullObjectType(): boolean { + get supportsFullObjectType (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): JavaScriptRenderer { return new JavaScriptRenderer(this, renderContext, getOptionValues(javaScriptOptions, untypedOptionValues)); } @@ -109,15 +112,15 @@ export const legalizeName = utf16LegalizeCharacters(isES3IdentifierPart); const identityNamingFunction = funPrefixNamer("properties", s => s); export class JavaScriptRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _jsOptions: OptionValues + private readonly _jsOptions: OptionValues, ) { super(targetLanguage, renderContext); } - protected nameStyle(original: string, upper: boolean): string { + protected nameStyle (original: string, upper: boolean): string { const acronyms = acronymStyle(this._jsOptions.acronymStyle); const words = splitIntoWords(original); return combineWords( @@ -128,57 +131,58 @@ export class JavaScriptRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isES3IdentifierStart + isES3IdentifierStart, ); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return identityNamingFunction; } - protected makeUnionMemberNamer(): null { + protected makeUnionMemberNamer (): null { return null; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, true)); } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { return directlyReachableSingleNamedType(type); } - protected makeNameForProperty( + protected makeNameForProperty ( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - _assignedName: string | undefined + _assignedName: string | undefined, ): Name | undefined { // Ignore the assigned name return super.makeNameForProperty(c, className, p, jsonName, undefined); } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - typeMapTypeFor(t: Type): Sourcelike { - if (["class", "object", "enum"].indexOf(t.kind) >= 0) { - return ['r("', this.nameForNamedType(t), '")']; + typeMapTypeFor (t: Type): Sourcelike { + if (["class", "object", "enum"].includes(t.kind)) { + return ["r(\"", this.nameForNamedType(t), "\")"]; } + return matchType( t, - _anyType => '"any"', - _nullType => `null`, - _boolType => `true`, - _integerType => `0`, - _doubleType => `3.14`, - _stringType => `""`, + _anyType => "\"any\"", + _nullType => "null", + _boolType => "true", + _integerType => "0", + _doubleType => "3.14", + _stringType => "\"\"", arrayType => ["a(", this.typeMapTypeFor(arrayType.items), ")"], _classType => panic("We handled this above"), mapType => ["m(", this.typeMapTypeFor(mapType.values), ")"], @@ -191,26 +195,28 @@ export class JavaScriptRenderer extends ConvenienceRenderer { if (transformedStringType.kind === "date-time") { return "Date"; } - return `""`; - } + + return "\"\""; + }, ); } - typeMapTypeForProperty(p: ClassProperty): Sourcelike { + typeMapTypeForProperty (p: ClassProperty): Sourcelike { const typeMap = this.typeMapTypeFor(p.type); if (!p.isOptional) { return typeMap; } + return ["u(undefined, ", typeMap, ")"]; } - emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void) { + emitBlock (source: Sourcelike, end: Sourcelike, emit: () => void) { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); } - emitTypeMap() { + emitTypeMap () { const { any: anyAnnotation } = this.typeAnnotations; this.emitBlock(`const typeMap${anyAnnotation} = `, ";", () => { @@ -218,24 +224,24 @@ export class JavaScriptRenderer extends ConvenienceRenderer { const additionalProperties = t.getAdditionalProperties(); const additional = additionalProperties !== undefined ? this.typeMapTypeFor(additionalProperties) : "false"; - this.emitLine('"', name, '": o(['); + this.emitLine("\"", name, "\": o(["); this.indent(() => { this.forEachClassProperty(t, "none", (propName, jsonName, property) => { this.emitLine( - '{ json: "', + "{ json: \"", utf16StringEscape(jsonName), - '", js: "', + "\", js: \"", modifySource(utf16StringEscape, propName), - '", typ: ', + "\", typ: ", this.typeMapTypeForProperty(property), - " }," + " },", ); }); }); this.emitLine("], ", additional, "),"); }); this.forEachEnum("none", (e, name) => { - this.emitLine('"', name, '": ['); + this.emitLine("\"", name, "\": ["); this.indent(() => { this.forEachEnumCase(e, "none", (_caseName, jsonName) => { this.emitLine(`"${utf16StringEscape(jsonName)}",`); @@ -246,32 +252,32 @@ export class JavaScriptRenderer extends ConvenienceRenderer { }); } - protected deserializerFunctionName(name: Name): Sourcelike { + protected deserializerFunctionName (name: Name): Sourcelike { return ["to", name]; } - protected deserializerFunctionLine(_t: Type, name: Name): Sourcelike { + protected deserializerFunctionLine (_t: Type, name: Name): Sourcelike { return ["function ", this.deserializerFunctionName(name), "(json)"]; } - protected serializerFunctionName(name: Name): Sourcelike { + protected serializerFunctionName (name: Name): Sourcelike { const camelCaseName = modifySource(camelCase, name); return [camelCaseName, "ToJson"]; } - protected serializerFunctionLine(_t: Type, name: Name): Sourcelike { + protected serializerFunctionLine (_t: Type, name: Name): Sourcelike { return ["function ", this.serializerFunctionName(name), "(value)"]; } - protected get moduleLine(): string | undefined { + protected get moduleLine (): string | undefined { return undefined; } - protected get castFunctionLines(): [string, string] { + protected get castFunctionLines (): [string, string] { return ["function cast(val, typ)", "function uncast(val, typ)"]; } - protected get typeAnnotations(): JavaScriptTypeAnnotations { + protected get typeAnnotations (): JavaScriptTypeAnnotations { return { any: "", anyArray: "", @@ -279,11 +285,11 @@ export class JavaScriptRenderer extends ConvenienceRenderer { string: "", stringArray: "", boolean: "", - never: "" + never: "", }; } - protected emitConvertModuleBody(): void { + protected emitConvertModuleBody (): void { const converter = (t: Type, name: Name) => { const typeMap = this.typeMapTypeFor(t); this.emitBlock([this.deserializerFunctionLine(t, name), " "], "", () => { @@ -324,7 +330,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { } } - protected emitConvertModuleHelpers(): void { + protected emitConvertModuleHelpers (): void { if (this._jsOptions.runtimeTypecheck) { const { any: anyAnnotation, @@ -332,7 +338,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { anyMap: anyMapAnnotation, string: stringAnnotation, stringArray: stringArrayAnnotation, - never: neverAnnotation + never: neverAnnotation, } = this.typeAnnotations; this.ensureBlankLine(); this @@ -428,10 +434,10 @@ function transform(val${anyAnnotation}, typ${anyAnnotation}, getProps${anyAnnota Object.getOwnPropertyNames(val).forEach(key => { if (!Object.prototype.hasOwnProperty.call(props, key)) { result[key] = ${ - this._jsOptions.runtimeTypecheckIgnoreUnknownProperties - ? `val[key]` - : `transform(val[key], additional, getProps, key, ref)` - }; + this._jsOptions.runtimeTypecheckIgnoreUnknownProperties + ? "val[key]" + : "transform(val[key], additional, getProps, key, ref)" +}; } }); return result; @@ -496,16 +502,17 @@ function r(name${stringAnnotation}) { } } - protected emitConvertModule(): void { + protected emitConvertModule (): void { this.ensureBlankLine(); this.emitMultiline( - `// Converts JSON ${this._jsOptions.rawType === "json" ? "strings" : "types"} to/from your types` + `// Converts JSON ${this._jsOptions.rawType === "json" ? "strings" : "types"} to/from your types`, ); if (this._jsOptions.runtimeTypecheck) { this.emitMultiline( - `// and asserts the results${this._jsOptions.rawType === "json" ? " of JSON.parse" : ""} at runtime` + `// and asserts the results${this._jsOptions.rawType === "json" ? " of JSON.parse" : ""} at runtime`, ); } + const moduleLine = this.moduleLine; if (moduleLine === undefined) { this.emitConvertModuleBody(); @@ -514,15 +521,15 @@ function r(name${stringAnnotation}) { } } - protected emitTypes(): void { + protected emitTypes (): void { return; } - protected emitUsageImportComment(): void { - this.emitLine('// const Convert = require("./file");'); + protected emitUsageImportComment (): void { + this.emitLine("// const Convert = require(\"./file\");"); } - protected emitUsageComments(): void { + protected emitUsageComments (): void { this.emitMultiline(`// To parse this data: //`); @@ -539,20 +546,20 @@ function r(name${stringAnnotation}) { } } - protected emitModuleExports(): void { + protected emitModuleExports (): void { this.ensureBlankLine(); this.emitBlock("module.exports = ", ";", () => { this.forEachTopLevel("none", (_, name) => { const serializer = this.serializerFunctionName(name); const deserializer = this.deserializerFunctionName(name); - this.emitLine('"', serializer, '": ', serializer, ","); - this.emitLine('"', deserializer, '": ', deserializer, ","); + this.emitLine("\"", serializer, "\": ", serializer, ","); + this.emitLine("\"", deserializer, "\": ", deserializer, ","); }); }); } - protected emitSourceStructure() { + protected emitSourceStructure () { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts index 7d6d90612..7c8927f24 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts @@ -1,21 +1,25 @@ import { TargetLanguage } from "../TargetLanguage"; -import { getOptionValues, Option, OptionValues, EnumOption } from "../RendererOptions"; -import { RenderContext } from "../Renderer"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { getOptionValues, EnumOption } from "../RendererOptions"; +import { type RenderContext } from "../Renderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { funPrefixNamer, Name, Namer } from "../Naming"; +import { type Name, type Namer } from "../Naming"; +import { funPrefixNamer } from "../Naming"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; +import { + type ClassProperty, + type ClassType, + type ObjectType, + type Sourcelike, + type Type, +} from ".."; import { capitalize, - ClassProperty, - ClassType, combineWords, firstUpperWordStyle, matchType, - ObjectType, panic, - Sourcelike, splitIntoWords, - Type } from ".."; import { allLowerWordStyle, utf16StringEscape } from "../support/Strings"; import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; @@ -33,29 +37,29 @@ export const javaScriptPropTypesOptions = { "Which module system to use", [ ["common-js", false], - ["es6", true] + ["es6", true], ], - "es6" - ) + "es6", + ), }; export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { - protected getOptions(): Option[] { + protected getOptions (): Array> { return [javaScriptPropTypesOptions.acronymStyle, javaScriptPropTypesOptions.converters]; } - constructor(displayName = "JavaScript PropTypes", names: string[] = ["javascript-prop-types"], extension = "js") { + constructor (displayName = "JavaScript PropTypes", names: string[] = ["javascript-prop-types"], extension = "js") { super(displayName, names, extension); } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): JavaScriptPropTypesRenderer { return new JavaScriptPropTypesRenderer( this, renderContext, - getOptionValues(javaScriptPropTypesOptions, untypedOptionValues) + getOptionValues(javaScriptPropTypesOptions, untypedOptionValues), ); } } @@ -63,15 +67,15 @@ export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { const identityNamingFunction = funPrefixNamer("properties", s => s); export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _jsOptions: OptionValues + private readonly _jsOptions: OptionValues, ) { super(targetLanguage, renderContext); } - protected nameStyle(original: string, upper: boolean): string { + protected nameStyle (original: string, upper: boolean): string { const acronyms = acronymStyle(this._jsOptions.acronymStyle); const words = splitIntoWords(original); return combineWords( @@ -82,43 +86,43 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isES3IdentifierStart + isES3IdentifierStart, ); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return identityNamingFunction; } - protected makeUnionMemberNamer(): null { + protected makeUnionMemberNamer (): null { return null; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { return directlyReachableSingleNamedType(type); } - protected makeNameForProperty( + protected makeNameForProperty ( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - _assignedName: string | undefined + _assignedName: string | undefined, ): Name | undefined { // Ignore the assigned name return super.makeNameForProperty(c, className, p, jsonName, undefined); } - typeMapTypeFor(t: Type, required = true): Sourcelike { - if (["class", "object", "enum"].indexOf(t.kind) >= 0) { + typeMapTypeFor (t: Type, required = true): Sourcelike { + if (["class", "object", "enum"].includes(t.kind)) { return ["_", this.nameForNamedType(t)]; } @@ -136,13 +140,13 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { _enumType => panic("Should already be handled."), unionType => { const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false) + this.typeMapTypeFor(type, false), ); return ["PropTypes.oneOfType([", ...arrayIntercalate(", ", children), "])"]; }, _transformedStringType => { return "PropTypes.string"; - } + }, ); if (required) { @@ -152,11 +156,11 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { return match; } - typeMapTypeForProperty(p: ClassProperty): Sourcelike { + typeMapTypeForProperty (p: ClassProperty): Sourcelike { return this.typeMapTypeFor(p.type); } - private importStatement(lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { + private importStatement (lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { if (this._jsOptions.moduleSystem) { return ["import ", lhs, " from ", moduleName, ";"]; } else { @@ -164,7 +168,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { } } - protected emitUsageComments(): void { + protected emitUsageComments (): void { // FIXME: Use the correct type name this.emitCommentLines( [ @@ -178,24 +182,24 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { "", "MyComponent.propTypes = {", " input: MyShape", - "};" + "};", ], - { lineStart: "// " } + { lineStart: "// " }, ); } - protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void) { + protected emitBlock (source: Sourcelike, end: Sourcelike, emit: () => void) { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); } - protected emitImports(): void { + protected emitImports (): void { this.ensureBlankLine(); - this.emitLine(this.importStatement("PropTypes", '"prop-types"')); + this.emitLine(this.importStatement("PropTypes", "\"prop-types\"")); } - private emitExport(name: Sourcelike, value: Sourcelike): void { + private emitExport (name: Sourcelike, value: Sourcelike): void { if (this._jsOptions.moduleSystem) { this.emitLine("export const ", name, " = ", value, ";"); } else { @@ -203,7 +207,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { } } - protected emitTypes(): void { + protected emitTypes (): void { this.ensureBlankLine(); this.forEachObject("none", (_type: ObjectType, name: Name) => { @@ -278,7 +282,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { }); } - private emitObject(name: Name, t: ObjectType) { + private emitObject (name: Name, t: ObjectType) { this.ensureBlankLine(); this.emitLine("_", name, " = PropTypes.shape({"); this.indent(() => { @@ -289,7 +293,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { this.emitLine("});"); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { diff --git a/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts b/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts index c3f105010..e818aaeb3 100644 --- a/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts +++ b/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts @@ -1,6 +1,6 @@ // Taken from https://github.com/Microsoft/TypeScript -function lookupInUnicodeMap(code: number, map: ReadonlyArray): boolean { +function lookupInUnicodeMap (code: number, map: readonly number[]): boolean { // Bail out quickly if it couldn't possibly be in the map. if (code < map[0]) { return false; @@ -45,24 +45,24 @@ const enum CharacterCodes { Z = 0x5a } -export function isES3IdentifierStart(ch: number): boolean { +export function isES3IdentifierStart (ch: number): boolean { return ( - (ch >= CharacterCodes.A && ch <= CharacterCodes.Z) || - (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || + ch >= CharacterCodes.A && ch <= CharacterCodes.Z || + ch >= CharacterCodes.a && ch <= CharacterCodes.z || ch === CharacterCodes.$ || ch === CharacterCodes._ || - (ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierStart)) + ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierStart) ); } -export function isES3IdentifierPart(ch: number): boolean { +export function isES3IdentifierPart (ch: number): boolean { return ( - (ch >= CharacterCodes.A && ch <= CharacterCodes.Z) || - (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || - (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) || + ch >= CharacterCodes.A && ch <= CharacterCodes.Z || + ch >= CharacterCodes.a && ch <= CharacterCodes.z || + ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ || - (ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierPart)) + ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierPart) ); } @@ -113,7 +113,7 @@ const unicodeES3IdentifierStart = [ 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65138, 65140, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, - 65482, 65487, 65490, 65495, 65498, 65500 + 65482, 65487, 65490, 65495, 65498, 65500, ]; const unicodeES3IdentifierPart = [ 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, @@ -152,5 +152,5 @@ const unicodeES3IdentifierPart = [ 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65056, 65059, 65075, 65076, 65101, 65103, 65136, 65138, 65140, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, - 65479, 65482, 65487, 65490, 65495, 65498, 65500 + 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts index 407b82300..53d636499 100644 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ b/packages/quicktype-core/src/language/Kotlin.ts @@ -1,10 +1,14 @@ import { iterableSome, arrayIntercalate } from "collection-utils"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { EnumOption, Option, StringOption, OptionValues, getOptionValues } from "../RendererOptions"; -import { Sourcelike, maybeAnnotated, modifySource } from "../Source"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated, modifySource } from "../Source"; import { allLowerWordStyle, allUpperWordStyle, @@ -19,23 +23,24 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap + utf32ConcatMap, } from "../support/Strings"; import { assertNever, mustNotHappen } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; +import { + type ClassProperty, + type EnumType, + type ObjectType, + type PrimitiveType, + type Type} from "../Type"; import { ArrayType, - ClassProperty, ClassType, - EnumType, MapType, - ObjectType, - PrimitiveType, - Type, - UnionType + UnionType, } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; export enum Framework { @@ -53,34 +58,34 @@ export const kotlinOptions = { ["just-types", Framework.None], ["jackson", Framework.Jackson], ["klaxon", Framework.Klaxon], - ["kotlinx", Framework.KotlinX] + ["kotlinx", Framework.KotlinX], ], - "klaxon" + "klaxon", ), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), }; export class KotlinTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Kotlin", ["kotlin"], "kt"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [kotlinOptions.framework, kotlinOptions.acronymStyle, kotlinOptions.packageName]; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): ConvenienceRenderer { const options = getOptionValues(kotlinOptions, untypedOptionValues); @@ -148,23 +153,23 @@ const keywords = [ "JsonObject", "JsonValue", "Converter", - "Klaxon" + "Klaxon", ]; -function isPartCharacter(codePoint: number): boolean { +function isPartCharacter (codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter(codePoint: number): boolean { +function isStartCharacter (codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function kotlinNameStyle( +function kotlinNameStyle ( isUpper: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle + acronymsStyle: (s: string) => string = allUpperWordStyle, ): string { const words = splitIntoWords(original); return combineWords( @@ -175,92 +180,92 @@ function kotlinNameStyle( isUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, "", - isStartCharacter + isStartCharacter, ); } -function unicodeEscape(codePoint: number): string { +function unicodeEscape (codePoint: number): string { return "\\u" + intToHex(codePoint, 4); } const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); -function stringEscape(s: string): string { +function stringEscape (s: string): string { // "$this" is a template string in Kotlin so we have to escape $ return _stringEscape(s).replace(/\$/g, "\\$"); } export class KotlinRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _kotlinOptions: OptionValues + protected readonly _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords; } - protected forbiddenForObjectProperties(_o: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_o: ObjectType, _classNamed: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected topLevelNameStyle(rawName: string): string { + protected topLevelNameStyle (rawName: string): string { return kotlinNameStyle(true, rawName); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return funPrefixNamer("lower", s => kotlinNameStyle(false, s, acronymStyle(this._kotlinOptions.acronymStyle))); } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return funPrefixNamer("upper", s => kotlinNameStyle(true, s) + "Value"); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock(line: Sourcelike, f: () => void, delimiter: "curly" | "paren" | "lambda" = "curly"): void { + protected emitBlock (line: Sourcelike, f: () => void, delimiter: "curly" | "paren" | "lambda" = "curly"): void { const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" ? ["(", ")"] : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); } - protected anySourceType(optional: string): Sourcelike { + protected anySourceType (optional: string): Sourcelike { return ["Any", optional]; } // (asarazan): I've broken out the following two functions // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType(arrayType: ArrayType, withIssues = false, _noOptional = false): Sourcelike { + protected arrayType (arrayType: ArrayType, withIssues = false, _noOptional = false): Sourcelike { return ["List<", this.kotlinType(arrayType.items, withIssues), ">"]; } - protected mapType(mapType: MapType, withIssues = false, _noOptional = false): Sourcelike { + protected mapType (mapType: MapType, withIssues = false, _noOptional = false): Sourcelike { return ["Map"]; } - protected kotlinType(t: Type, withIssues = false, noOptional = false): Sourcelike { + protected kotlinType (t: Type, withIssues = false, noOptional = false): Sourcelike { const optional = noOptional ? "" : "?"; return matchType( t, @@ -282,15 +287,15 @@ export class KotlinRenderer extends ConvenienceRenderer { const nullable = nullableFromUnion(unionType); if (nullable !== null) return [this.kotlinType(nullable, withIssues), optional]; return this.nameForNamedType(unionType); - } + }, ); } - protected emitUsageHeader(): void { + protected emitUsageHeader (): void { // To be overridden } - protected emitHeader(): void { + protected emitHeader (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -302,23 +307,23 @@ export class KotlinRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitLine(["typealias ", name, " = ArrayList<", elementType, ">"]); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); this.emitLine(["typealias ", name, " = HashMap"]); } - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + protected emitEmptyClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitClassAnnotations(c, className); this.emitLine("class ", className, "()"); } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition (c: ClassType, className: Name): void { if (c.getProperties().size === 0) { this.emitEmptyClassDefinition(c, className); return; @@ -372,19 +377,19 @@ export class KotlinRenderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(c, className); } - protected emitClassDefinitionMethods(_c: ClassType, _className: Name) { + protected emitClassDefinitionMethods (_c: ClassType, _className: Name) { this.emitLine(")"); } - protected emitClassAnnotations(_c: Type, _className: Name) { + protected emitClassAnnotations (_c: Type, _className: Name) { // to be overridden } - protected renameAttribute(_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>) { + protected renameAttribute (_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>) { // to be overridden } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["enum class ", enumName], () => { @@ -395,8 +400,8 @@ export class KotlinRenderer extends ConvenienceRenderer { }); } - protected emitUnionDefinition(u: UnionType, unionName: Name): void { - function sortBy(t: Type): string { + protected emitUnionDefinition (u: UnionType, unionName: Name): void { + function sortBy (t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -412,15 +417,16 @@ export class KotlinRenderer extends ConvenienceRenderer { this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { table.push([ ["class ", name, "(val value: ", this.kotlinType(t), ")"], - [" : ", unionName, "()"] + [" : ", unionName, "()"], ]); }); if (maybeNull !== null) { table.push([ ["class ", this.nameForUnionMember(u, maybeNull), "()"], - [" : ", unionName, "()"] + [" : ", unionName, "()"], ]); } + this.emitTable(table); } @@ -428,16 +434,16 @@ export class KotlinRenderer extends ConvenienceRenderer { }); } - protected emitUnionDefinitionMethods( + protected emitUnionDefinitionMethods ( _u: UnionType, _nonNulls: ReadonlySet, _maybeNull: PrimitiveType | null, - _unionName: Name + _unionName: Name, ) { // to be overridden } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.emitHeader(); // Top-level arrays, maps @@ -453,21 +459,21 @@ export class KotlinRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n) + (u, n) => this.emitUnionDefinition(u, n), ); } } export class KotlinKlaxonRenderer extends KotlinRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues + _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext, _kotlinOptions); } - private unionMemberFromJsonValue(t: Type, e: Sourcelike): Sourcelike { + private unionMemberFromJsonValue (t: Type, e: Sourcelike): Sourcelike { return matchType( t, _anyType => [e, ".inside"], @@ -480,11 +486,11 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { _classType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], _mapType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], enumType => [e, ".string?.let { ", this.kotlinType(enumType), ".fromValue(it) }"], - _unionType => mustNotHappen() + _unionType => mustNotHappen(), ); } - private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { + private unionMemberJsonValueGuard (t: Type, _e: Sourcelike): Sourcelike { return matchType( t, _anyType => "is Any", @@ -501,11 +507,11 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { // This could be stricter, but for now we don't allow strings // and enums in the same union _enumType => "is String", - _unionType => mustNotHappen() + _unionType => mustNotHappen(), ); } - protected emitUsageHeader(): void { + protected emitUsageHeader (): void { this.emitLine("// To parse the JSON, install Klaxon and do:"); this.emitLine("//"); this.forEachTopLevel("none", (_, name) => { @@ -513,18 +519,18 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { }); } - protected emitHeader(): void { + protected emitHeader (): void { super.emitHeader(); this.emitLine("import com.beust.klaxon.*"); const hasUnions = iterableSome( this.typeGraph.allNamedTypes(), - t => t instanceof UnionType && nullableFromUnion(t) === null + t => t instanceof UnionType && nullableFromUnion(t) === null, ); const hasEmptyObjects = iterableSome( this.typeGraph.allNamedTypes(), - c => c instanceof ClassType && c.getProperties().size === 0 + c => c instanceof ClassType && c.getProperties().size === 0, ); if (hasUnions || this.haveEnums || hasEmptyObjects) { this.emitGenericConverter(); @@ -534,18 +540,19 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { if (hasEmptyObjects) { converters.push([[".convert(JsonObject::class,"], [" { it.obj!! },"], [" { it.toJsonString() })"]]); } + this.forEachEnum("none", (_, name) => { converters.push([ [".convert(", name, "::class,"], [" { ", name, ".fromValue(it.string!!) },"], - [' { "\\"${it.value}\\"" })'] + [" { \"\\\"${it.value}\\\"\" })"], ]); }); this.forEachUnion("none", (_, name) => { converters.push([ [".convert(", name, "::class,"], [" { ", name, ".fromJson(it) },"], - [" { it.toJson() }, true)"] + [" { it.toJson() }, true)"], ]); }); @@ -556,7 +563,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitBlock( ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], @@ -569,14 +576,14 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { name, "(klaxon.parseArray<", elementType, - ">(json)!!)" + ">(json)!!)", ); }); - } + }, ); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); this.emitBlock( [ @@ -586,7 +593,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { elementType, ">) : HashMap(elements)" + ">(elements)", ], () => { this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); @@ -598,36 +605,38 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { this.emitLine( "klaxon.parseJsonObject(java.io.StringReader(json)) as Map" + ">", ); }, - "paren" + "paren", ); }); - } + }, ); } - private klaxonRenameAttribute(propName: Name, jsonName: string, ignore = false): Sourcelike | undefined { + private klaxonRenameAttribute (propName: Name, jsonName: string, ignore = false): Sourcelike | undefined { const escapedName = stringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; const properties: Sourcelike[] = []; if (namesDiffer) { - properties.push(['name = "', escapedName, '"']); + properties.push(["name = \"", escapedName, "\""]); } + if (ignore) { properties.push("ignored = true"); } + return properties.length === 0 ? undefined : ["@Json(", arrayIntercalate(", ", properties), ")"]; } - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + protected emitEmptyClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("typealias ", className, " = JsonObject"); } - protected emitClassDefinitionMethods(c: ClassType, className: Name) { + protected emitClassDefinitionMethods (c: ClassType, className: Name) { const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); if (isTopLevel) { this.emitBlock(")", () => { @@ -642,14 +651,14 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } } - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { + protected renameAttribute (name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { const rename = this.klaxonRenameAttribute(name, jsonName); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); } } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { @@ -671,33 +680,33 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { }); } - private emitGenericConverter(): void { + private emitGenericConverter (): void { this.ensureBlankLine(); this.emitLine( - "private fun Klaxon.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonValue) -> T, toJson: (T) -> String, isUnion: Boolean = false) =" + "private fun Klaxon.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonValue) -> T, toJson: (T) -> String, isUnion: Boolean = false) =", ); this.indent(() => { this.emitLine("this.converter(object: Converter {"); this.indent(() => { - this.emitLine(`@Suppress("UNCHECKED_CAST")`); + this.emitLine("@Suppress(\"UNCHECKED_CAST\")"); this.emitTable([ ["override fun toJson(value: Any)", " = toJson(value as T)"], ["override fun fromJson(jv: JsonValue)", " = fromJson(jv) as Any"], [ "override fun canConvert(cls: Class<*>)", - " = cls == k.java || (isUnion && cls.superclass == k.java)" - ] + " = cls == k.java || (isUnion && cls.superclass == k.java)", + ], ]); }); this.emitLine("})"); }); } - protected emitUnionDefinitionMethods( + protected emitUnionDefinitionMethods ( u: UnionType, nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, - unionName: Name + unionName: Name, ) { this.ensureBlankLine(); this.emitLine("public fun toJson(): String = klaxon.toJsonString(when (this) {"); @@ -708,8 +717,9 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { }); if (maybeNull !== null) { const name = this.nameForUnionMember(u, maybeNull); - toJsonTable.push([["is ", name], [' -> "null"']]); + toJsonTable.push([["is ", name], [" -> \"null\""]]); } + this.emitTable(toJsonTable); }); this.emitLine("})"); @@ -721,13 +731,14 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { table.push([ [this.unionMemberJsonValueGuard(t, "jv.inside")], - [" -> ", name, "(", this.unionMemberFromJsonValue(t, "jv"), "!!)"] + [" -> ", name, "(", this.unionMemberFromJsonValue(t, "jv"), "!!)"], ]); }); if (maybeNull !== null) { const name = this.nameForUnionMember(u, maybeNull); table.push([[this.unionMemberJsonValueGuard(maybeNull, "jv.inside")], [" -> ", name, "()"]]); } + table.push([["else"], [" -> throw IllegalArgumentException()"]]); this.emitTable(table); }); @@ -737,15 +748,15 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } export class KotlinJacksonRenderer extends KotlinRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues + _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext, _kotlinOptions); } - private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { + private unionMemberJsonValueGuard (t: Type, _e: Sourcelike): Sourcelike { return matchType( t, _anyType => "is Any", @@ -762,11 +773,11 @@ export class KotlinJacksonRenderer extends KotlinRenderer { // This could be stricter, but for now we don't allow strings // and enums in the same union _enumType => "is TextNode", - _unionType => mustNotHappen() + _unionType => mustNotHappen(), ); } - protected emitUsageHeader(): void { + protected emitUsageHeader (): void { this.emitLine("// To parse the JSON, install jackson-module-kotlin and do:"); this.emitLine("//"); this.forEachTopLevel("none", (_, name) => { @@ -774,7 +785,7 @@ export class KotlinJacksonRenderer extends KotlinRenderer { }); } - protected emitHeader(): void { + protected emitHeader (): void { super.emitHeader(); this.emitMultiline(`import com.fasterxml.jackson.annotation.* @@ -788,11 +799,11 @@ import com.fasterxml.jackson.module.kotlin.*`); const hasUnions = iterableSome( this.typeGraph.allNamedTypes(), - t => t instanceof UnionType && nullableFromUnion(t) === null + t => t instanceof UnionType && nullableFromUnion(t) === null, ); const hasEmptyObjects = iterableSome( this.typeGraph.allNamedTypes(), - c => c instanceof ClassType && c.getProperties().size === 0 + c => c instanceof ClassType && c.getProperties().size === 0, ); if (hasUnions || this.haveEnums || hasEmptyObjects) { this.emitGenericConverter(); @@ -806,14 +817,14 @@ import com.fasterxml.jackson.module.kotlin.*`); converters.push([ ["convert(", name, "::class,"], [" { ", name, ".fromValue(it.asText()) },"], - [' { "\\"${it.value}\\"" })'] + [" { \"\\\"${it.value}\\\"\" })"], ]); }); this.forEachUnion("none", (_, name) => { converters.push([ ["convert(", name, "::class,"], [" { ", name, ".fromJson(it) },"], - [" { it.toJson() }, true)"] + [" { it.toJson() }, true)"], ]); }); @@ -831,7 +842,7 @@ import com.fasterxml.jackson.module.kotlin.*`); this.emitLine("}"); } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitBlock( ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], @@ -841,11 +852,11 @@ import com.fasterxml.jackson.module.kotlin.*`); this.emitBlock("companion object", () => { this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); }); - } + }, ); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); this.emitBlock( [ @@ -855,7 +866,7 @@ import com.fasterxml.jackson.module.kotlin.*`); elementType, ">) : HashMap(elements)" + ">(elements)", ], () => { this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); @@ -863,15 +874,15 @@ import com.fasterxml.jackson.module.kotlin.*`); this.emitBlock("companion object", () => { this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); }); - } + }, ); } - private jacksonRenameAttribute( + private jacksonRenameAttribute ( propName: Name, jsonName: string, required: boolean, - ignore = false + ignore = false, ): Sourcelike | undefined { const escapedName = stringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; @@ -880,8 +891,9 @@ import com.fasterxml.jackson.module.kotlin.*`); const propertyOpts: Sourcelike[] = []; if (namesDiffer || isPrefixBool) { - propertyOpts.push('"' + escapedName + '"'); + propertyOpts.push("\"" + escapedName + "\""); } + if (required) { propertyOpts.push("required=true"); } @@ -895,16 +907,17 @@ import com.fasterxml.jackson.module.kotlin.*`); properties.push("@get:JsonIgnore"); properties.push("@field:JsonIgnore"); } + return properties.length === 0 ? undefined : properties; } - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + protected emitEmptyClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("typealias ", className, " = JsonNode"); } - protected emitClassDefinitionMethods(c: ClassType, className: Name) { + protected emitClassDefinitionMethods (c: ClassType, className: Name) { const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); if (isTopLevel) { this.emitBlock(")", () => { @@ -919,14 +932,14 @@ import com.fasterxml.jackson.module.kotlin.*`); } } - protected renameAttribute(name: Name, jsonName: string, required: boolean, meta: Array<() => void>) { + protected renameAttribute (name: Name, jsonName: string, required: boolean, meta: Array<() => void>) { const rename = this.jacksonRenameAttribute(name, jsonName, required); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); } } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { @@ -948,7 +961,7 @@ import com.fasterxml.jackson.module.kotlin.*`); }); } - private emitGenericConverter(): void { + private emitGenericConverter (): void { this.ensureBlankLine(); this.emitMultiline(` @Suppress("UNCHECKED_CAST") @@ -962,11 +975,11 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso })`); } - protected emitUnionDefinitionMethods( + protected emitUnionDefinitionMethods ( u: UnionType, nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, - unionName: Name + unionName: Name, ) { this.ensureBlankLine(); this.emitLine("fun toJson(): String = mapper.writeValueAsString(when (this) {"); @@ -977,8 +990,9 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso }); if (maybeNull !== null) { const name = this.nameForUnionMember(u, maybeNull); - toJsonTable.push([["is ", name], [' -> "null"']]); + toJsonTable.push([["is ", name], [" -> \"null\""]]); } + this.emitTable(toJsonTable); }); this.emitLine("})"); @@ -994,6 +1008,7 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso const name = this.nameForUnionMember(u, maybeNull); table.push([[this.unionMemberJsonValueGuard(maybeNull, "jn")], [" -> ", name, "()"]]); } + table.push([["else"], [" -> throw IllegalArgumentException()"]]); this.emitTable(table); }); @@ -1007,37 +1022,39 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso * TODO: Union, Any, Top Level Array, Top Level Map */ export class KotlinXRenderer extends KotlinRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues + _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext, _kotlinOptions); } - protected anySourceType(optional: string): Sourcelike { + protected anySourceType (optional: string): Sourcelike { return ["JsonElement", optional]; } - protected arrayType(arrayType: ArrayType, withIssues = false, noOptional = false): Sourcelike { + protected arrayType (arrayType: ArrayType, withIssues = false, noOptional = false): Sourcelike { const valType = this.kotlinType(arrayType.items, withIssues, true); const name = this.sourcelikeToString(valType); if (name === "JsonObject" || name === "JsonElement") { return "JsonArray"; } + return super.arrayType(arrayType, withIssues, noOptional); } - protected mapType(mapType: MapType, withIssues = false, noOptional = false): Sourcelike { + protected mapType (mapType: MapType, withIssues = false, noOptional = false): Sourcelike { const valType = this.kotlinType(mapType.values, withIssues, true); const name = this.sourcelikeToString(valType); if (name === "JsonObject" || name === "JsonElement") { return "JsonObject"; } + return super.mapType(mapType, withIssues, noOptional); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); if (elementType === "JsonObject") { this.emitLine(["typealias ", name, " = JsonObject"]); @@ -1046,12 +1063,12 @@ export class KotlinXRenderer extends KotlinRenderer { } } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitLine(["typealias ", name, " = JsonArray<", elementType, ">"]); } - protected emitUsageHeader(): void { + protected emitUsageHeader (): void { this.emitLine("// To parse the JSON, install kotlin's serialization plugin and do:"); this.emitLine("//"); const table: Sourcelike[][] = []; @@ -1060,13 +1077,13 @@ export class KotlinXRenderer extends KotlinRenderer { table.push([ "// val ", modifySource(camelCase, name), - ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)` + ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)`, ]); }); this.emitTable(table); } - protected emitHeader(): void { + protected emitHeader (): void { super.emitHeader(); this.emitLine("import kotlinx.serialization.*"); @@ -1075,27 +1092,28 @@ export class KotlinXRenderer extends KotlinRenderer { this.emitLine("import kotlinx.serialization.encoding.*"); } - protected emitClassAnnotations(_c: Type, _className: Name) { + protected emitClassAnnotations (_c: Type, _className: Name) { this.emitLine("@Serializable"); } - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { + protected renameAttribute (name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { const rename = this._rename(name, jsonName); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); } } - private _rename(propName: Name, jsonName: string): Sourcelike | undefined { + private _rename (propName: Name, jsonName: string): Sourcelike | undefined { const escapedName = stringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; if (namesDiffer) { - return ['@SerialName("', escapedName, '")']; + return ["@SerialName(\"", escapedName, "\")"]; } + return undefined; } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine(["@Serializable"]); diff --git a/packages/quicktype-core/src/language/Objective-C.ts b/packages/quicktype-core/src/language/Objective-C.ts index b1a44e899..00235121c 100644 --- a/packages/quicktype-core/src/language/Objective-C.ts +++ b/packages/quicktype-core/src/language/Objective-C.ts @@ -1,10 +1,13 @@ import { iterableSome, iterableFirst, mapContains, mapFirst, mapSome } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { Type, ClassType, EnumType, ArrayType, MapType, UnionType, ClassProperty } from "../Type"; +import { type ClassProperty } from "../Type"; +import { Type, ClassType, EnumType, ArrayType, MapType, UnionType } from "../Type"; import { matchType, nullableFromUnion, isAnyOrNull } from "../TypeUtils"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { Sourcelike, modifySource } from "../Source"; +import { type Name} from "../Naming"; +import { Namer, funPrefixNamer } from "../Naming"; +import { type Sourcelike} from "../Source"; +import { modifySource } from "../Source"; import { splitIntoWords, combineWords, @@ -16,17 +19,21 @@ import { stringEscape, addPrefixIfNecessary, repeatString, - fastIsUpperCase + fastIsUpperCase, } from "../support/Strings"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { StringOption, BooleanOption, EnumOption, Option, getOptionValues, OptionValues } from "../RendererOptions"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { StringOption, BooleanOption, EnumOption, getOptionValues } from "../RendererOptions"; import { assert, defined } from "../support/Support"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; import unicode from "unicode-properties"; export type MemoryAttribute = "assign" | "strong" | "copy"; -export type OutputFeatures = { interface: boolean; implementation: boolean }; +export interface OutputFeatures { + implementation: boolean; interface: boolean; +} const DEBUG = false; const DEFAULT_CLASS_PREFIX = "QT"; @@ -35,38 +42,38 @@ export const objcOptions = { features: new EnumOption("features", "Interface and implementation", [ ["all", { interface: true, implementation: true }], ["interface", { interface: true, implementation: false }], - ["implementation", { interface: false, implementation: true }] + ["implementation", { interface: false, implementation: true }], ]), justTypes: new BooleanOption("just-types", "Plain types only", false), marshallingFunctions: new BooleanOption("functions", "C-style functions", false), classPrefix: new StringOption("class-prefix", "Class prefix", "PREFIX", DEFAULT_CLASS_PREFIX), - extraComments: new BooleanOption("extra-comments", "Extra comments", false) + extraComments: new BooleanOption("extra-comments", "Extra comments", false), }; export class ObjectiveCTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Objective-C", ["objc", "objective-c", "objectivec"], "m"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ objcOptions.justTypes, objcOptions.classPrefix, objcOptions.features, objcOptions.extraComments, - objcOptions.marshallingFunctions + objcOptions.marshallingFunctions, ]; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): ObjectiveCRenderer { return new ObjectiveCRenderer(this, renderContext, getOptionValues(objcOptions, untypedOptionValues)); } } -function typeNameStyle(prefix: string, original: string): string { +function typeNameStyle (prefix: string, original: string): string { const words = splitIntoWords(original); const result = combineWords( words, @@ -76,12 +83,12 @@ function typeNameStyle(prefix: string, original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); return addPrefixIfNecessary(prefix, result); } -function propertyNameStyle(original: string, isBool = false): string { +function propertyNameStyle (original: string, isBool = false): string { // Objective-C developers are uncomfortable with property "id" // so we use an alternate name in this special case. if (original === "id") { @@ -93,14 +100,14 @@ function propertyNameStyle(original: string, isBool = false): string { if (isBool) { if (words.length === 0) { words = [{ word: "flag", isAcronym: false }]; - } else if (!words[0].isAcronym && booleanPrefixes.indexOf(words[0].word) < 0) { + } else if (!words[0].isAcronym && !booleanPrefixes.includes(words[0].word)) { words = [{ word: "is", isAcronym: false }, ...words]; } } // Properties cannot even begin with any of the forbidden names // For example, properies named new* are treated differently by ARC - if (words.length > 0 && forbiddenPropertyNames.indexOf(words[0].word) >= 0) { + if (words.length > 0 && forbiddenPropertyNames.includes(words[0].word)) { words = [{ word: "the", isAcronym: false }, ...words]; } @@ -112,7 +119,7 @@ function propertyNameStyle(original: string, isBool = false): string { allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -164,7 +171,7 @@ const keywords = [ "unsigned", "void", "volatile", - "while" + "while", ]; const forbiddenPropertyNames = [ @@ -176,7 +183,7 @@ const forbiddenPropertyNames = [ "mutableCopy", "superclass", "debugDescription", - "new" + "new", ]; const booleanPrefixes = [ @@ -196,16 +203,16 @@ const booleanPrefixes = [ "requires", "require", "needs", - "need" + "need", ]; -function isStartCharacter(utf16Unit: number): boolean { +function isStartCharacter (utf16Unit: number): boolean { return unicode.isAlphabetic(utf16Unit) || utf16Unit === 0x5f; // underscore } -function isPartCharacter(utf16Unit: number): boolean { +function isPartCharacter (utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); @@ -213,7 +220,7 @@ const legalizeName = utf16LegalizeCharacters(isPartCharacter); const staticEnumValuesIdentifier = "values"; const forbiddenForEnumCases = ["new", staticEnumValuesIdentifier]; -function splitExtension(filename: string): [string, string] { +function splitExtension (filename: string): [string, string] { const i = filename.lastIndexOf("."); const extension = i !== -1 ? filename.split(".").pop() : "m"; filename = i !== -1 ? filename.slice(0, i) : filename; @@ -222,12 +229,13 @@ function splitExtension(filename: string): [string, string] { export class ObjectiveCRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; + private readonly _classPrefix: string; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); @@ -240,98 +248,99 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } } - private inferClassPrefix(name: string): string { + private inferClassPrefix (name: string): string { const l = name.length; let firstNonUpper = 0; while (firstNonUpper < l && fastIsUpperCase(name.charCodeAt(firstNonUpper))) { firstNonUpper += 1; } + if (firstNonUpper < 2) return DEFAULT_CLASS_PREFIX; return name.slice(0, firstNonUpper - 1); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: forbiddenPropertyNames, includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: forbiddenForEnumCases, includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("types", rawName => typeNameStyle(this._classPrefix, rawName)); } - protected namerForObjectProperty(_: ClassType, p: ClassProperty): Namer { + protected namerForObjectProperty (_: ClassType, p: ClassProperty): Namer { // TODO why is underscore being removed? return new Namer("properties", s => propertyNameStyle(s, p.type.kind === "bool"), [ "_", "the", "one", "some", - "another" + "another", ]); } - protected makeUnionMemberNamer(): null { + protected makeUnionMemberNamer (): null { return null; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return new Namer("enum-cases", propertyNameStyle, []); } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { return type; } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: "/// " }); } - protected emitBlock(line: Sourcelike, f: () => void): void { + protected emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected emitMethod(declaration: Sourcelike, f: () => void) { + protected emitMethod (declaration: Sourcelike, f: () => void) { this.emitLine(declaration); this.emitLine("{"); this.indent(f); this.emitLine("}"); } - protected emitExtraComments(...comments: Sourcelike[]) { + protected emitExtraComments (...comments: Sourcelike[]) { if (!this._options.extraComments) return; for (const comment of comments) { this.emitLine("// ", comment); } } - protected startFile(basename: Sourcelike, extension: string): void { + protected startFile (basename: Sourcelike, extension: string): void { assert(this._currentFilename === undefined, "Previous file wasn't finished"); // FIXME: The filenames should actually be Sourcelikes, too this._currentFilename = `${this.sourcelikeToString(basename)}.${extension}`; } - protected finishFile(): void { + protected finishFile (): void { super.finishFile(defined(this._currentFilename)); this._currentFilename = undefined; } - protected memoryAttribute(t: Type, isNullable: boolean): MemoryAttribute { + protected memoryAttribute (t: Type, isNullable: boolean): MemoryAttribute { return matchType( t, _anyType => "copy", _nullType => "copy", - _boolType => (isNullable ? "strong" : "assign"), - _integerType => (isNullable ? "strong" : "assign"), - _doubleType => (isNullable ? "strong" : "assign"), + _boolType => isNullable ? "strong" : "assign", + _integerType => isNullable ? "strong" : "assign", + _doubleType => isNullable ? "strong" : "assign", _stringType => "copy", _arrayType => "copy", _classType => "strong", @@ -340,19 +349,19 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.memoryAttribute(nullable, true) : "copy"; - } + }, ); } - protected objcType(t: Type, nullableOrBoxed = false): [Sourcelike, string] { + protected objcType (t: Type, nullableOrBoxed = false): [Sourcelike, string] { return matchType<[Sourcelike, string]>( t, _anyType => ["id", ""], // For now, we're treating nulls just like any _nullType => ["id", ""], - _boolType => (nullableOrBoxed ? ["NSNumber", " *"] : ["BOOL", ""]), - _integerType => (nullableOrBoxed ? ["NSNumber", " *"] : ["NSInteger", ""]), - _doubleType => (nullableOrBoxed ? ["NSNumber", " *"] : ["double", ""]), + _boolType => nullableOrBoxed ? ["NSNumber", " *"] : ["BOOL", ""], + _integerType => nullableOrBoxed ? ["NSNumber", " *"] : ["NSInteger", ""], + _doubleType => nullableOrBoxed ? ["NSNumber", " *"] : ["double", ""], _stringType => ["NSString", " *"], arrayType => { const itemType = arrayType.items; @@ -361,6 +370,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (isAnyOrNull(itemType)) { return ["NSArray", " *"]; } + return [["NSArray<", itemTypeName, ">"], " *"]; }, classType => [this.nameForNamedType(classType), " *"], @@ -369,11 +379,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.objcType(nullable, true) : ["id", ""]; - } + }, ); } - private jsonType(t: Type): [Sourcelike, string] { + private jsonType (t: Type): [Sourcelike, string] { return matchType<[Sourcelike, string]>( t, _anyType => ["id", ""], @@ -390,11 +400,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.jsonType(nullable) : ["id", ""]; - } + }, ); } - protected fromDynamicExpression(t: Type, ...dynamic: Sourcelike[]): Sourcelike { + protected fromDynamicExpression (t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, _anyType => dynamic, @@ -410,17 +420,17 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.fromDynamicExpression(nullable, dynamic) : dynamic; - } + }, ); } - protected toDynamicExpression(t: Type, typed: Sourcelike): Sourcelike { + protected toDynamicExpression (t: Type, typed: Sourcelike): Sourcelike { return matchType( t, _anyType => ["NSNullify(", typed, ")"], _nullType => ["NSNullify(", typed, ")"], // Sadly, KVC - _boolType => [typed, ` ? @YES : @NO`], + _boolType => [typed, " ? @YES : @NO"], _integerType => typed, _doubleType => typed, _stringType => typed, @@ -429,6 +439,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { // TODO check each value type return typed; } + return ["map(", typed, ", λ(id x, ", this.toDynamicExpression(arrayType.items, "x"), "))"]; }, _classType => ["[", typed, " JSONDictionary]"], @@ -437,6 +448,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { // TODO check each value type return typed; } + return ["map(", typed, ", λ(id x, ", this.toDynamicExpression(mapType.values, "x"), "))"]; }, _enumType => ["[", typed, " value]"], @@ -452,11 +464,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { // TODO support unions return typed; } - } + }, ); } - protected implicitlyConvertsFromJSON(t: Type): boolean { + protected implicitlyConvertsFromJSON (t: Type): boolean { if (t instanceof ClassType) { return false; } else if (t instanceof EnumType) { @@ -480,11 +492,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } } - protected implicitlyConvertsToJSON(t: Type): boolean { + protected implicitlyConvertsToJSON (t: Type): boolean { return this.implicitlyConvertsFromJSON(t) && "bool" !== t.kind; } - protected emitPropertyAssignment(propertyName: Name, jsonName: string, propertyType: Type) { + protected emitPropertyAssignment (propertyName: Name, jsonName: string, propertyType: Type) { const name = ["_", propertyName]; matchType( propertyType, @@ -504,7 +516,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { name, ", ", ["λ(id x, ", this.fromDynamicExpression(itemType, "x"), ")"], - ");" + ");", ); }, enumType => this.emitLine(name, " = ", this.fromDynamicExpression(enumType, ["(id)", name]), ";"), @@ -516,43 +528,43 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { // TODO This is a union, but for now we just leave it dynamic this.emitLine(name, " = ", this.fromDynamicExpression(unionType, name), ";"); } - } + }, ); } - protected emitPrivateClassInterface(_: ClassType, name: Name): void { + protected emitPrivateClassInterface (_: ClassType, name: Name): void { this.emitLine("@interface ", name, " (JSONConversion)"); this.emitLine("+ (instancetype)fromJSONDictionary:(NSDictionary *)dict;"); this.emitLine("- (NSDictionary *)JSONDictionary;"); this.emitLine("@end"); } - protected pointerAwareTypeName(t: Type | [Sourcelike, string]): Sourcelike { + protected pointerAwareTypeName (t: Type | [Sourcelike, string]): Sourcelike { const name = t instanceof Type ? this.objcType(t) : t; const isPointer = name[1] !== ""; return isPointer ? name : [name, " "]; } - private emitNonClassTopLevelTypedef(t: Type, name: Name): void { + private emitNonClassTopLevelTypedef (t: Type, name: Name): void { let nonPointerTypeName = this.objcType(t)[0]; this.emitLine("typedef ", nonPointerTypeName, " ", name, ";"); } - private topLevelFromDataPrototype(name: Name): Sourcelike { + private topLevelFromDataPrototype (name: Name): Sourcelike { return [name, " *_Nullable ", name, "FromData(NSData *data, NSError **error)"]; } - private topLevelFromJSONPrototype(name: Name): Sourcelike { + private topLevelFromJSONPrototype (name: Name): Sourcelike { return [name, " *_Nullable ", name, "FromJSON(NSString *json, NSStringEncoding encoding, NSError **error)"]; } - private topLevelToDataPrototype(name: Name, pad = false): Sourcelike { + private topLevelToDataPrototype (name: Name, pad = false): Sourcelike { const parameter = this.variableNameForTopLevel(name); const padding = pad ? repeatString(" ", this.sourcelikeToString(name).length - "NSData".length) : ""; return ["NSData", padding, " *_Nullable ", name, "ToData(", name, " *", parameter, ", NSError **error)"]; } - private topLevelToJSONPrototype(name: Name, pad = false): Sourcelike { + private topLevelToJSONPrototype (name: Name, pad = false): Sourcelike { const parameter = this.variableNameForTopLevel(name); const padding = pad ? repeatString(" ", this.sourcelikeToString(name).length - "NSString".length) : ""; return [ @@ -564,31 +576,31 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { name, " *", parameter, - ", NSStringEncoding encoding, NSError **error)" + ", NSStringEncoding encoding, NSError **error)", ]; } - private emitTopLevelFunctionDeclarations(_: Type, name: Name): void { + private emitTopLevelFunctionDeclarations (_: Type, name: Name): void { this.emitLine(this.topLevelFromDataPrototype(name), ";"); this.emitLine(this.topLevelFromJSONPrototype(name), ";"); this.emitLine(this.topLevelToDataPrototype(name, true), ";"); this.emitLine(this.topLevelToJSONPrototype(name, true), ";"); } - private emitTryCatchAsError(inTry: () => void, inCatch: () => void) { + private emitTryCatchAsError (inTry: () => void, inCatch: () => void) { this.emitLine("@try {"); this.indent(inTry); this.emitLine("} @catch (NSException *exception) {"); this.indent(() => { this.emitLine( - `*error = [NSError errorWithDomain:@"JSONSerialization" code:-1 userInfo:@{ @"exception": exception }];` + "*error = [NSError errorWithDomain:@\"JSONSerialization\" code:-1 userInfo:@{ @\"exception\": exception }];", ); inCatch(); }); this.emitLine("}"); } - private emitTopLevelFunctions(t: Type, name: Name): void { + private emitTopLevelFunctions (t: Type, name: Name): void { const parameter = this.variableNameForTopLevel(name); this.ensureBlankLine(); @@ -596,11 +608,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitTryCatchAsError( () => { this.emitLine( - "id json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:error];" + "id json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:error];", ); this.emitLine("return *error ? nil : ", this.fromDynamicExpression(t, "json"), ";"); }, - () => this.emitLine("return nil;") + () => this.emitLine("return nil;"), ); }); @@ -615,11 +627,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { () => { this.emitLine("id json = ", this.toDynamicExpression(t, parameter), ";"); this.emitLine( - "NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:error];" + "NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:error];", ); this.emitLine("return *error ? nil : data;"); }, - () => this.emitLine("return nil;") + () => this.emitLine("return nil;"), ); }); @@ -630,7 +642,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { }); } - private emitClassInterface(t: ClassType, className: Name): void { + private emitClassInterface (t: ClassType, className: Name): void { const isTopLevel = mapContains(this.topLevels, t); this.emitDescription(this.descriptionForType(t)); @@ -644,10 +656,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (property.type.isNullable) { attributes.push("nullable"); } + attributes.push(this.memoryAttribute(property.type, property.type.isNullable)); return [ ["@property ", ["(", attributes.join(", "), ")"], " "], - [this.pointerAwareTypeName(property.type), name, ";"] + [this.pointerAwareTypeName(property.type), name, ";"], ]; }); @@ -655,18 +668,19 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (t.getProperties().size > 0) this.ensureBlankLine(); this.emitLine( - "+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;" + "+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;", ); this.emitLine("+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error;"); this.emitLine( - "- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;" + "- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;", ); this.emitLine("- (NSData *_Nullable)toData:(NSError *_Nullable *)error;"); } + this.emitLine("@end"); } - protected hasIrregularProperties(t: ClassType) { + protected hasIrregularProperties (t: ClassType) { let irregular = false; this.forEachClassProperty(t, "none", (name, jsonName) => { irregular = irregular || stringEscape(jsonName) !== this.sourcelikeToString(name); @@ -674,7 +688,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return irregular; } - protected hasUnsafeProperties(t: ClassType) { + protected hasUnsafeProperties (t: ClassType) { let unsafe = false; this.forEachClassProperty(t, "none", (_, __, property) => { unsafe = unsafe || !this.implicitlyConvertsToJSON(property.type); @@ -683,7 +697,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } // TODO Implement NSCopying - private emitClassImplementation(t: ClassType, className: Name): void { + private emitClassImplementation (t: ClassType, className: Name): void { const isTopLevel = mapContains(this.topLevels, t); const hasIrregularProperties = this.hasIrregularProperties(t); @@ -696,7 +710,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("return properties = properties ? properties : @{"); this.indent(() => { this.forEachClassProperty(t, "none", (name, jsonName) => - this.emitLine(`@"${stringEscape(jsonName)}": @"`, name, `",`) + this.emitLine(`@"${stringEscape(jsonName)}": @"`, name, "\","), ); }); this.emitLine("};"); @@ -708,14 +722,14 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error", () => { this.emitLine("return ", className, "FromData(data, error);"); - } + }, ); this.ensureBlankLine(); this.emitMethod( "+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error", () => { this.emitLine("return ", className, "FromJSON(json, encoding, error);"); - } + }, ); this.ensureBlankLine(); } @@ -763,17 +777,17 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine( "id dict = [[self dictionaryWithValuesForKeys:", className, - ".properties.allValues] mutableCopy];" + ".properties.allValues] mutableCopy];", ); this.ensureBlankLine(); if (hasIrregularProperties) { this.emitExtraComments("Rewrite property names that differ in JSON"); this.emitBlock(["for (id jsonName in ", className, ".properties)"], () => { - this.emitLine(`id propertyName = `, className, `.properties[jsonName];`); - this.emitBlock(`if (![jsonName isEqualToString:propertyName])`, () => { - this.emitLine(`dict[jsonName] = dict[propertyName];`); - this.emitLine(`[dict removeObjectForKey:propertyName];`); + this.emitLine("id propertyName = ", className, ".properties[jsonName];"); + this.emitBlock("if (![jsonName isEqualToString:propertyName])", () => { + this.emitLine("dict[jsonName] = dict[propertyName];"); + this.emitLine("[dict removeObjectForKey:propertyName];"); }); }); } @@ -787,7 +801,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (!this.implicitlyConvertsToJSON(property.type)) { const key = stringEscape(jsonKey); const name = ["_", propertyName]; - this.emitLine('@"', key, '": ', this.toDynamicExpression(property.type, name), ","); + this.emitLine("@\"", key, "\": ", this.toDynamicExpression(property.type, name), ","); } }); }); @@ -800,15 +814,15 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (isTopLevel) { this.ensureBlankLine(); - this.emitMethod(`- (NSData *_Nullable)toData:(NSError *_Nullable *)error`, () => { + this.emitMethod("- (NSData *_Nullable)toData:(NSError *_Nullable *)error", () => { this.emitLine("return ", className, "ToData(self, error);"); }); this.ensureBlankLine(); this.emitMethod( - `- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error`, + "- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error", () => { this.emitLine("return ", className, "ToJSON(self, encoding, error);"); - } + }, ); } } @@ -816,13 +830,13 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - protected emitMark(label: string) { + protected emitMark (label: string) { this.ensureBlankLine(); this.emitLine(`#pragma mark - ${label}`); this.ensureBlankLine(); } - protected variableNameForTopLevel(name: Name): Sourcelike { + protected variableNameForTopLevel (name: Name): Sourcelike { const camelCaseName = modifySource(serialized => { // 1. remove class prefix serialized = serialized.slice(this._classPrefix.length); @@ -832,7 +846,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return camelCaseName; } - private emitPseudoEnumInterface(enumType: EnumType, enumName: Name) { + private emitPseudoEnumInterface (enumType: EnumType, enumName: Name) { this.emitDescription(this.descriptionForType(enumType)); this.emitLine("@interface ", enumName, " : NSObject"); @@ -844,7 +858,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - private emitPseudoEnumImplementation(enumType: EnumType, enumName: Name) { + private emitPseudoEnumImplementation (enumType: EnumType, enumName: Name) { this.emitLine("@implementation ", enumName); const instances = [enumName, ".", staticEnumValuesIdentifier]; @@ -857,11 +871,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { staticEnumValuesIdentifier, " ? ", staticEnumValuesIdentifier, - " : @{" + " : @{", ); this.indent(() => { this.forEachEnumCase(enumType, "none", (_, jsonValue) => { - const value = ['@"', stringEscape(jsonValue), '"']; + const value = ["@\"", stringEscape(jsonValue), "\""]; this.emitLine(value, ": [[", enumName, " alloc] initWithValue:", value, "],"); }); }); @@ -877,15 +891,15 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { name, " { return ", instances, - '[@"', + "[@\"", stringEscape(jsonValue), - '"]; }' + "\"]; }", ); }); this.ensureBlankLine(); this.emitMethod("+ (instancetype _Nullable)withValue:(NSString *)value", () => - this.emitLine("return ", instances, "[value];") + this.emitLine("return ", instances, "[value];"), ); this.ensureBlankLine(); @@ -899,13 +913,14 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - protected emitSourceStructure(proposedFilename: string): void { + protected emitSourceStructure (proposedFilename: string): void { const fileMode = proposedFilename !== "stdout"; if (!fileMode) { // We don't have a filename, so we use a top-level name const firstTopLevel = defined(mapFirst(this.topLevels)); proposedFilename = this.sourcelikeToString(this.nameForNamedType(firstTopLevel)) + ".m"; } + const [filename, extension] = splitExtension(proposedFilename); if (this._options.features.interface) { @@ -927,13 +942,13 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { " *", this.variableNameForTopLevel(topLevelName), " = ", - fromJsonExpression + fromJsonExpression, ); }); } this.ensureBlankLine(); - this.emitLine(`#import `); + this.emitLine("#import "); this.ensureBlankLine(); // Emit @class declarations for top-level array+maps and classes @@ -941,7 +956,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "none", (_: ClassType, className: Name) => this.emitLine("@class ", className, ";"), (_, enumName) => this.emitLine("@class ", enumName, ";"), - () => null + () => null, ); this.ensureBlankLine(); @@ -958,7 +973,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading-and-interposing", (t, n) => this.emitNonClassTopLevelTypedef(t, n), - t => !(t instanceof ClassType) + t => !(t instanceof ClassType), ); const hasTopLevelNonClassTypes = iterableSome(this.topLevels, ([_, t]) => !(t instanceof ClassType)); @@ -970,7 +985,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { (t, n) => this.emitTopLevelFunctionDeclarations(t, n), // Objective-C developers get freaked out by C functions, so we don't // declare them for top-level object types (we always need them for non-object types) - t => this._options.marshallingFunctions || !(t instanceof ClassType) + t => this._options.marshallingFunctions || !(t instanceof ClassType), ); } @@ -979,7 +994,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassInterface(c, className), () => null, - () => null + () => null, ); this.ensureBlankLine(); @@ -996,11 +1011,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (!this._options.justTypes) { this.ensureBlankLine(); this.emitExtraComments("Shorthand for simple blocks"); - this.emitLine(`#define λ(decl, expr) (^(decl) { return (expr); })`); + this.emitLine("#define λ(decl, expr) (^(decl) { return (expr); })"); this.ensureBlankLine(); this.emitExtraComments("nil → NSNull conversion for JSON dictionaries"); this.emitBlock("static id NSNullify(id _Nullable x)", () => - this.emitLine("return (x == nil || x == NSNull.null) ? NSNull.null : x;") + this.emitLine("return (x == nil || x == NSNull.null) ? NSNull.null : x;"), ); this.ensureBlankLine(); this.emitLine("NS_ASSUME_NONNULL_BEGIN"); @@ -1016,7 +1031,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, className: Name) => this.emitPrivateClassInterface(c, className), () => null, - () => null + () => null, ); if (this.haveEnums) { @@ -1024,10 +1039,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitExtraComments( "These enum-like reference types are needed so that enum", - "values can be contained by NSArray and NSDictionary." + "values can be contained by NSArray and NSDictionary.", ); this.ensureBlankLine(); } + this.forEachEnum("leading-and-interposing", (t, n) => this.emitPseudoEnumImplementation(t, n)); } @@ -1043,7 +1059,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassImplementation(c, className), () => null, - () => null + () => null, ); if (!this._options.justTypes) { @@ -1054,19 +1070,21 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.finishFile(); } } - private get needsMap(): boolean { + + private get needsMap (): boolean { // TODO this isn't complete (needs union support, for example) - function needsMap(t: Type): boolean { + function needsMap (t: Type): boolean { return ( t instanceof MapType || t instanceof ArrayType || - (t instanceof ClassType && mapSome(t.getProperties(), p => needsMap(p.type))) + t instanceof ClassType && mapSome(t.getProperties(), p => needsMap(p.type)) ); } + return iterableSome(this.typeGraph.allTypesUnordered(), needsMap); } - protected emitMapFunction() { + protected emitMapFunction () { if (this.needsMap) { this.emitMultiline(`static id map(id collection, id (^f)(id value)) { id result = nil; diff --git a/packages/quicktype-core/src/language/Php.ts b/packages/quicktype-core/src/language/Php.ts index 670b09cc1..87c9e2b1c 100644 --- a/packages/quicktype-core/src/language/Php.ts +++ b/packages/quicktype-core/src/language/Php.ts @@ -1,9 +1,13 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { DependencyName, funPrefixNamer, Name, Namer } from "../Naming"; -import { RenderContext } from "../Renderer"; -import { BooleanOption, getOptionValues, Option, OptionValues } from "../RendererOptions"; -import { maybeAnnotated, Sourcelike } from "../Source"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer } from "../Naming"; +import { DependencyName, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { BooleanOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike } from "../Source"; +import { maybeAnnotated } from "../Source"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; import { allLowerWordStyle, @@ -17,13 +21,13 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../support/Strings"; import { defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { ClassProperty, ClassType, EnumType, Type, UnionType } from "../Type"; +import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; -import { StringTypeMapping, TransformedStringTypeKind, PrimitiveStringTypeKind } from ".."; +import { type StringTypeMapping, type TransformedStringTypeKind, type PrimitiveStringTypeKind } from ".."; import * as _ from "lodash"; export const phpOptions = { @@ -31,28 +35,28 @@ export const phpOptions = { fastGet: new BooleanOption("fast-get", "getter without validation", false), withSet: new BooleanOption("with-set", "Create Setter", false), withClosing: new BooleanOption("with-closing", "PHP Closing Tag", false), - acronymStyle: acronymOption(AcronymStyleOptions.Pascal) + acronymStyle: acronymOption(AcronymStyleOptions.Pascal), }; export class PhpTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("PHP", ["php"], "php"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return _.values(phpOptions); } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): PhpRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): PhpRenderer { const options = getOptionValues(phpOptions, untypedOptionValues); return new PhpRenderer(this, renderContext, options); } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date"); // TODO is not implemented yet mapping.set("time", "time"); // TODO is not implemented yet @@ -64,22 +68,22 @@ export class PhpTargetLanguage extends TargetLanguage { export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); -function isStartCharacter(codePoint: number): boolean { +function isStartCharacter (codePoint: number): boolean { if (codePoint === 0x5f) return true; // underscore return isAscii(codePoint) && isLetter(codePoint); } -function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); +function isPartCharacter (codePoint: number): boolean { + return isStartCharacter(codePoint) || isAscii(codePoint) && isDigit(codePoint); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); -export function phpNameStyle( +export function phpNameStyle ( startWithUpper: boolean, upperUnderscore: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle + acronymsStyle: (s: string) => string = allUpperWordStyle, ): string { const words = splitIntoWords(original); return combineWords( @@ -90,97 +94,100 @@ export function phpNameStyle( upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, upperUnderscore ? "_" : "", - isStartCharacter + isStartCharacter, ); } export interface FunctionNames { + readonly from: Name; readonly getter: Name; + readonly sample: Name; readonly setter: Name; - readonly validate: Name; - readonly from: Name; readonly to: Name; - readonly sample: Name; + readonly validate: Name; } export class PhpRenderer extends ConvenienceRenderer { private readonly _gettersAndSettersForPropertyName = new Map(); + private _haveEmittedLeadingComments = false; + protected readonly _converterClassname: string = "Converter"; + protected readonly _converterKeywords: string[] = []; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues + protected readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return this.getNameStyling("typeNamingFunction"); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return this.getNameStyling("enumCaseNamingFunction"); } - protected unionNeedsName(u: UnionType): boolean { + protected unionNeedsName (u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + protected namedTypeToNameForTopLevel (type: Type): Type | undefined { return directlyReachableSingleNamedType(type); } - protected makeNamesForPropertyGetterAndSetter( + protected makeNamesForPropertyGetterAndSetter ( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name + name: Name, ): FunctionNames { const getterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `get_${lookup(name)}` + lookup => `get_${lookup(name)}`, ); const setterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `set_${lookup(name)}` + lookup => `set_${lookup(name)}`, ); const validateName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `validate_${lookup(name)}` + lookup => `validate_${lookup(name)}`, ); const fromName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `from_${lookup(name)}` + lookup => `from_${lookup(name)}`, ); const toName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `to_${lookup(name)}` + lookup => `to_${lookup(name)}`, ); const sampleName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `sample_${lookup(name)}` + lookup => `sample_${lookup(name)}`, ); return { getter: getterName, @@ -188,16 +195,16 @@ export class PhpRenderer extends ConvenienceRenderer { validate: validateName, from: fromName, to: toName, - sample: sampleName + sample: sampleName, }; } - protected makePropertyDependencyNames( + protected makePropertyDependencyNames ( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); @@ -207,26 +214,26 @@ export class PhpRenderer extends ConvenienceRenderer { getterAndSetterNames.validate, getterAndSetterNames.to, getterAndSetterNames.from, - getterAndSetterNames.sample + getterAndSetterNames.sample, ]; } - private getNameStyling(convention: string): Namer { - const styling: { [key: string]: Namer } = { + private getNameStyling (convention: string): Namer { + const styling: { [key: string]: Namer, } = { typeNamingFunction: funPrefixNamer("types", n => - phpNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)) + phpNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)), ), propertyNamingFunction: funPrefixNamer("properties", n => - phpNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)) + phpNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)), ), enumCaseNamingFunction: funPrefixNamer("enum-cases", n => - phpNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)) - ) + phpNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)), + ), }; return styling[convention]; } - protected startFile(_basename: Sourcelike): void { + protected startFile (_basename: Sourcelike): void { this.ensureBlankLine(); if (!this._haveEmittedLeadingComments && this.leadingComments !== undefined) { this.emitComments(this.leadingComments); @@ -235,30 +242,31 @@ export class PhpRenderer extends ConvenienceRenderer { } } - protected finishFile(): void { + protected finishFile (): void { // empty } - protected emitFileHeader(fileName: Sourcelike, _imports: string[]): void { + protected emitFileHeader (fileName: Sourcelike, _imports: string[]): void { this.startFile(fileName); this.emitLine("// This is a autogenerated file:", fileName); this.ensureBlankLine(); } - public emitDescriptionBlock(lines: Sourcelike[]): void { + public emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - public emitBlock(line: Sourcelike, f: () => void): void { + public emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected phpType(_reference: boolean, t: Type, isOptional = false, prefix = "?", suffix = ""): Sourcelike { - function optionalize(s: Sourcelike) { + protected phpType (_reference: boolean, t: Type, isOptional = false, prefix = "?", suffix = ""): Sourcelike { + function optionalize (s: Sourcelike) { return [isOptional ? prefix : "", s, isOptional ? suffix : ""]; } + return matchType( t, _anyType => maybeAnnotated(isOptional, anyTypeIssueAnnotation, "Object"), @@ -278,23 +286,27 @@ export class PhpRenderer extends ConvenienceRenderer { }, transformedStringType => { if (transformedStringType.kind === "time") { - throw Error('transformedStringType.kind === "time"'); + throw Error("transformedStringType.kind === \"time\""); } + if (transformedStringType.kind === "date") { - throw Error('transformedStringType.kind === "date"'); + throw Error("transformedStringType.kind === \"date\""); } + if (transformedStringType.kind === "date-time") { return "DateTime"; } + if (transformedStringType.kind === "uuid") { - throw Error('transformedStringType.kind === "uuid"'); + throw Error("transformedStringType.kind === \"uuid\""); } + return "string"; - } + }, ); } - protected phpDocConvertType(className: Name, t: Type): Sourcelike { + protected phpDocConvertType (className: Name, t: Type): Sourcelike { return matchType( t, _anyType => "any", @@ -312,18 +324,20 @@ export class PhpRenderer extends ConvenienceRenderer { if (nullable !== null) { return [this.phpDocConvertType(className, nullable), "|null"]; } + throw Error("union are not supported"); }, transformedStringType => { if (transformedStringType.kind === "date-time") { return "DateTime"; } - throw Error('transformedStringType.kind === "unknown"'); - } + + throw Error("transformedStringType.kind === \"unknown\""); + }, ); } - protected phpConvertType(className: Name, t: Type): Sourcelike { + protected phpConvertType (className: Name, t: Type): Sourcelike { return matchType( t, _anyType => "any", @@ -341,19 +355,21 @@ export class PhpRenderer extends ConvenienceRenderer { if (nullable !== null) { return ["?", this.phpConvertType(className, nullable)]; } + throw Error("union are not supported"); }, transformedStringType => { if (transformedStringType.kind === "date-time") { return "string"; } - throw Error('transformedStringType.kind === "unknown"'); - } + + throw Error("transformedStringType.kind === \"unknown\""); + }, ); } - protected phpToObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { - return matchType( + protected phpToObjConvert (className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { + matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), _nullType => this.emitLine(...lhs, ...args, "; /*null*/"), @@ -391,6 +407,7 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine("}"); return; } + throw Error("union are not supported"); }, transformedStringType => { @@ -398,22 +415,23 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine(...lhs, ...args, "->format(DateTimeInterface::ISO8601);"); return; } - throw Error('transformedStringType.kind === "unknown"'); - } + + throw Error("transformedStringType.kind === \"unknown\""); + }, ); } - private transformDateTime(className: Name, attrName: Sourcelike, scopeAttrName: Sourcelike[]) { + private transformDateTime (className: Name, attrName: Sourcelike, scopeAttrName: Sourcelike[]) { this.emitBlock(["if (!is_a(", scopeAttrName, ", 'DateTime'))"], () => - this.emitLine("throw new Exception('Attribute Error:", className, "::", attrName, "');") + this.emitLine("throw new Exception('Attribute Error:", className, "::", attrName, "');"), ); // if (lhs !== undefined) { // this.emitLine(lhs, "$tmp;"); // } } - protected phpFromObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { - return matchType( + protected phpFromObjConvert (className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { + matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), _nullType => this.emitLine(...lhs, ...args, "; /*null*/"), @@ -452,6 +470,7 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine("}"); return; } + throw Error("union are not supported"); }, transformedStringType => { @@ -461,20 +480,21 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine("return $tmp;"); return; } - throw Error('transformedStringType.kind === "unknown"'); - } + + throw Error("transformedStringType.kind === \"unknown\""); + }, ); } - protected phpSampleConvert( + protected phpSampleConvert ( className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[], idx: number, - suffix: Sourcelike + suffix: Sourcelike, ) { - return matchType( + matchType( t, _anyType => this.emitLine( @@ -490,7 +510,7 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/" + "*/", ), _nullType => this.emitLine(...lhs, "null", suffix, " /*", "" + idx, ":", args, "*/"), _boolType => this.emitLine(...lhs, "true", suffix, " /*", "" + idx, ":", args, "*/"), @@ -510,7 +530,7 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/" + "*/", ), arrayType => { this.emitLine(...lhs, " array("); @@ -529,7 +549,7 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/" + "*/", ), mapType => { this.emitBlock(["function sample(): stdClass"], () => { @@ -546,33 +566,36 @@ export class PhpRenderer extends ConvenienceRenderer { this.phpSampleConvert(className, nullable, lhs, args, idx, suffix); return; } + throw Error("union are not supported:" + unionType); }, transformedStringType => { if (transformedStringType.kind === "date-time") { - const x = _.pad("" + (1 + (idx % 31)), 2, "0"); + const x = _.pad("" + (1 + idx % 31), 2, "0"); this.emitLine( ...lhs, "DateTime::createFromFormat(DateTimeInterface::ISO8601, '", `2020-12-${x}T12:${x}:${x}+00:00`, "')", - suffix + suffix, ); // this.emitLine("return sample();"); return; } - throw Error('transformedStringType.kind === "unknown"'); - } + + throw Error("transformedStringType.kind === \"unknown\""); + }, ); } - private phpValidate(className: Name, t: Type, attrName: Sourcelike, scopeAttrName: string) { + private phpValidate (className: Name, t: Type, attrName: Sourcelike, scopeAttrName: string) { const is = (isfn: string, myT: Name = className) => { this.emitBlock(["if (!", isfn, "(", scopeAttrName, "))"], () => - this.emitLine('throw new Exception("Attribute Error:', myT, "::", attrName, '");') + this.emitLine("throw new Exception(\"Attribute Error:", myT, "::", attrName, "\");"), ); }; - return matchType( + + matchType( t, _anyType => is("defined"), _nullType => is("is_null"), @@ -609,6 +632,7 @@ export class PhpRenderer extends ConvenienceRenderer { }); return; } + throw Error("not implemented"); }, transformedStringType => { @@ -616,17 +640,19 @@ export class PhpRenderer extends ConvenienceRenderer { this.transformDateTime(className, attrName, [scopeAttrName]); return; } + throw Error(`transformedStringType.kind === ${transformedStringType.kind}`); - } + }, ); } - protected emitFromMethod(names: FunctionNames, p: ClassProperty, className: Name, _name: Name, desc?: string[]) { + protected emitFromMethod (names: FunctionNames, p: ClassProperty, className: Name, _name: Name, desc?: string[]) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); this.emitLine(" *"); } + // this.emitLine(" * @param ", this.phpType(false, p.type, false, "", "|null")); this.emitLine(" * @param ", this.phpConvertType(className, p.type), " $value"); this.emitLine(" * @throws Exception"); @@ -639,20 +665,22 @@ export class PhpRenderer extends ConvenienceRenderer { "(", this.phpConvertType(className, p.type), " $value): ", - this.phpType(false, p.type) + this.phpType(false, p.type), ], () => { - this.phpFromObjConvert(className, p.type, ["return "], [`$value`]); + this.phpFromObjConvert(className, p.type, ["return "], ["$value"]); // this.emitLine("return $ret;"); - } + }, ); } - protected emitToMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + + protected emitToMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); this.emitLine(" *"); } + this.emitLine(" * @throws Exception"); this.emitLine(" * @return ", this.phpConvertType(className, p.type)); this.emitLine(" */"); @@ -663,12 +691,14 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine("throw new Exception('never get to this ", className, "::", name, "');"); }); } - protected emitValidateMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + + protected emitValidateMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); this.emitLine(" *"); } + this.emitLine(" * @param ", this.phpType(false, p.type, false, "", "|null")); this.emitLine(" * @return bool"); this.emitLine(" * @throws Exception"); @@ -676,21 +706,24 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitBlock( ["public static function ", names.validate, "(", this.phpType(false, p.type), " $value): bool"], () => { - this.phpValidate(className, p.type, name, `$value`); + this.phpValidate(className, p.type, name, "$value"); this.emitLine("return true;"); - } + }, ); } - protected emitGetMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + + protected emitGetMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { if (this._options.withGet) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); this.emitLine(" *"); } + if (!this._options.fastGet) { - this.emitLine(` * @throws Exception`); + this.emitLine(" * @throws Exception"); } + const rendered = this.phpType(false, p.type); this.emitLine(" * @return ", rendered); this.emitLine(" */"); @@ -706,7 +739,7 @@ export class PhpRenderer extends ConvenienceRenderer { className, "::", name, - "');" + "');", ); } else { this.emitLine("return $this->", name, ";"); @@ -714,15 +747,17 @@ export class PhpRenderer extends ConvenienceRenderer { }); } } - protected emitSetMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + + protected emitSetMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { if (this._options.withSet) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); this.emitLine(" *"); } + this.emitLine(" * @param ", this.phpType(false, p.type, false, "", "|null")); - this.emitLine(` * @throws Exception`); + this.emitLine(" * @throws Exception"); this.emitLine(" */"); this.emitBlock(["public function ", names.setter, "(", this.phpType(false, p.type), " $value)"], () => { this.emitBlock(["if (", className, "::", names.validate, "($value)) "], () => { @@ -731,13 +766,14 @@ export class PhpRenderer extends ConvenienceRenderer { }); } } - protected emitSampleMethod( + + protected emitSampleMethod ( names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc: string[] | undefined, - idx: number + idx: number, ) { if (this._options.withGet) { this.emitLine("/**"); @@ -745,6 +781,7 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine(" * ", desc); this.emitLine(" *"); } + const rendered = this.phpType(false, p.type); this.emitLine(" * @return ", rendered); this.emitLine(" */"); @@ -754,7 +791,7 @@ export class PhpRenderer extends ConvenienceRenderer { } } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition (c: ClassType, className: Name): void { this.emitFileHeader(className, []); this.emitBlock(["class ", className], () => { @@ -767,7 +804,7 @@ export class PhpRenderer extends ConvenienceRenderer { "; // json:", jsonName, " ", - p.type.isNullable ? "Optional" : "Required" + p.type.isNullable ? "Optional" : "Required", ); }); @@ -807,7 +844,7 @@ export class PhpRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitBlock( - ["/**\n", ` * @throws Exception\n`, ` * @return bool\n`, " */\n", "public function validate(): bool"], + ["/**\n", " * @throws Exception\n", " * @return bool\n", " */\n", "public function validate(): bool"], () => { let lines: Sourcelike[][] = []; let p = "return "; @@ -819,17 +856,17 @@ export class PhpRenderer extends ConvenienceRenderer { lines.forEach((line, jdx) => { this.emitLine(...line, lines.length === jdx + 1 ? ";" : ""); }); - } + }, ); this.ensureBlankLine(); this.emitBlock( [ "/**\n", - ` * @return stdClass\n`, - ` * @throws Exception\n`, + " * @return stdClass\n", + " * @throws Exception\n", " */\n", - "public function to(): stdClass " + "public function to(): stdClass ", ], () => { this.emitLine("$out = new stdClass();"); @@ -838,21 +875,21 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine("$out->{'", jsonName, "'} = $this->", names.to, "();"); }); this.emitLine("return $out;"); - } + }, ); this.ensureBlankLine(); this.emitBlock( [ "/**\n", - ` * @param stdClass $obj\n`, - ` * @return `, + " * @param stdClass $obj\n", + " * @return ", className, - `\n`, - ` * @throws Exception\n`, + "\n", + " * @throws Exception\n", " */\n", "public static function from(stdClass $obj): ", - className + className, ], () => { if (this._options.fastGet) { @@ -861,6 +898,7 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine(className, "::", names.validate, "($this->", name, ", true);"); }); } + this.emitLine("return new ", className, "("); let comma = " "; this.forEachClassProperty(c, "none", (name, jsonName) => { @@ -869,7 +907,7 @@ export class PhpRenderer extends ConvenienceRenderer { comma = ","; }); this.emitLine(");"); - } + }, ); this.ensureBlankLine(); this.emitBlock( @@ -883,33 +921,33 @@ export class PhpRenderer extends ConvenienceRenderer { comma = ","; }); this.emitLine(");"); - } + }, ); }); this.finishFile(); } - protected emitUnionAttributes(_u: UnionType, _unionName: Name): void { + protected emitUnionAttributes (_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionSerializer(_u: UnionType, _unionName: Name): void { + protected emitUnionSerializer (_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionDefinition(_u: UnionType, _unionName: Name): void { + protected emitUnionDefinition (_u: UnionType, _unionName: Name): void { throw Error("emitUnionDefinition not implemented"); } - protected emitEnumSerializationAttributes(_e: EnumType) { + protected emitEnumSerializationAttributes (_e: EnumType) { // Empty } - protected emitEnumDeserializationAttributes(_e: EnumType) { + protected emitEnumDeserializationAttributes (_e: EnumType) { // Empty } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitFileHeader(enumName, []); this.emitDescription(this.descriptionForType(e)); const caseNames: Sourcelike[] = []; @@ -937,18 +975,18 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitBlock( [ "/**\n", - ` * @param `, + " * @param ", enumName, - `\n`, - ` * @return `, + "\n", + " * @return ", enumSerdeType, - `\n`, - ` * @throws Exception\n`, + "\n", + " * @throws Exception\n", " */\n", "public static function to(", enumName, " $obj): ", - enumSerdeType + enumSerdeType, ], () => { this.emitLine("switch ($obj->enum) {"); @@ -962,13 +1000,13 @@ export class PhpRenderer extends ConvenienceRenderer { name, "->enum: return '", stringEscape(jsonName), - "';" + "';", ); }); }); this.emitLine("}"); this.emitLine("throw new Exception('the give value is not an enum-value.');"); - } + }, ); this.ensureBlankLine(); this.emitEnumDeserializationAttributes(e); @@ -976,14 +1014,14 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitBlock( [ "/**\n", - ` * @param mixed\n`, - ` * @return `, + " * @param mixed\n", + " * @return ", enumName, "\n", - ` * @throws Exception\n`, + " * @throws Exception\n", " */\n", "public static function from($obj): ", - enumName + enumName, ], () => { this.emitLine("switch ($obj) {"); @@ -994,36 +1032,37 @@ export class PhpRenderer extends ConvenienceRenderer { }); }); this.emitLine("}"); - this.emitLine('throw new Exception("Cannot deserialize ', enumName, '");'); - } + this.emitLine("throw new Exception(\"Cannot deserialize ", enumName, "\");"); + }, ); this.ensureBlankLine(); this.emitBlock( - ["/**\n", ` * @return `, enumName, "\n", " */\n", "public static function sample(): ", enumName], + ["/**\n", " * @return ", enumName, "\n", " */\n", "public static function sample(): ", enumName], () => { const lines: Sourcelike[] = []; this.forEachEnumCase(e, "none", name => { lines.push([enumName, "::$", name]); }); this.emitLine("return ", lines[0], ";"); - } + }, ); }); this.emitLine(enumName, "::init();"); this.finishFile(); } - protected emitSourceStructure(givenFilename: string): void { + protected emitSourceStructure (givenFilename: string): void { this.emitLine(" this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n) + (u, n) => this.emitUnionDefinition(u, n), ); if (this._options.withClosing) { this.emitLine("?>"); } + super.finishFile(defined(givenFilename)); } } diff --git a/packages/quicktype-core/src/language/Pike.ts b/packages/quicktype-core/src/language/Pike.ts index d2d9541b7..0e9716278 100644 --- a/packages/quicktype-core/src/language/Pike.ts +++ b/packages/quicktype-core/src/language/Pike.ts @@ -1,10 +1,14 @@ -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { Option } from "../RendererOptions"; -import { RenderContext } from "../Renderer"; -import { MultiWord, Sourcelike, multiWord, parenIfNeeded, singleWord } from "../Source"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Option } from "../RendererOptions"; +import { type RenderContext } from "../Renderer"; +import { type MultiWord, type Sourcelike} from "../Source"; +import { multiWord, parenIfNeeded, singleWord } from "../Source"; import { TargetLanguage } from "../TargetLanguage"; -import { Type, ClassType, EnumType, UnionType, ArrayType, MapType, PrimitiveType } from "../Type"; +import { type Type, type ClassType, type EnumType, type UnionType} from "../Type"; +import { ArrayType, MapType, PrimitiveType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; import { legalizeCharacters, isLetterOrUnderscoreOrDigit, stringEscape, makeNameStyle } from "../support/Strings"; @@ -62,7 +66,7 @@ const keywords = [ "sscanf", "switch", "typeof", - "global" + "global", ]; const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); @@ -71,20 +75,21 @@ const namingFunction = funPrefixNamer("genericNamer", makeNameStyle("underscore" const namedTypeNamingFunction = funPrefixNamer("typeNamer", makeNameStyle("pascal", legalizeName)); export class PikeTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Pike", ["pike", "pikelang"], "pmod"); } - protected getOptions(): Option[] { + + protected getOptions (): Array> { return []; } - protected makeRenderer(renderContext: RenderContext): PikeRenderer { + protected makeRenderer (renderContext: RenderContext): PikeRenderer { return new PikeRenderer(this, renderContext); } } export class PikeRenderer extends ConvenienceRenderer { - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.emitInformationComment(); this.ensureBlankLine(); this.forEachTopLevel( @@ -95,56 +100,58 @@ export class PikeRenderer extends ConvenienceRenderer { this.emitTopLevelConverter(t, name); this.ensureBlankLine(); }, - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); this.ensureBlankLine(); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassDefinition(c, className), (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n) + (u, n) => this.emitUnion(u, n), ); } - protected get enumCasesInGlobalNamespace(): boolean { + protected get enumCasesInGlobalNamespace (): boolean { return true; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return enumNamingFunction; } - protected makeNamedTypeNamer(): Namer { + + protected makeNamedTypeNamer (): Namer { return namedTypeNamingFunction; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return namingFunction; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return namingFunction; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return [...keywords]; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected sourceFor(t: Type): MultiWord { - if (["class", "object", "enum"].indexOf(t.kind) >= 0) { + protected sourceFor (t: Type): MultiWord { + if (["class", "object", "enum"].includes(t.kind)) { return singleWord(this.nameForNamedType(t)); } + return matchType( t, _anyType => singleWord("mixed"), @@ -170,11 +177,11 @@ export class PikeRenderer extends ConvenienceRenderer { } else { return singleWord(this.nameForNamedType(unionType)); } - } + }, ); } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitBlock(["class ", className], () => { this.emitClassMembers(c); @@ -185,20 +192,20 @@ export class PikeRenderer extends ConvenienceRenderer { this.emitDecodingFunction(className, c); } - protected emitEnum(e: EnumType, enumName: Name): void { + protected emitEnum (e: EnumType, enumName: Name): void { this.emitBlock([e.kind, " ", enumName], () => { let table: Sourcelike[][] = []; this.forEachEnumCase(e, "none", (name, jsonName) => { table.push([ - [name, ' = "', stringEscape(jsonName), '", '], - ['// json: "', jsonName, '"'] + [name, " = \"", stringEscape(jsonName), "\", "], + ["// json: \"", jsonName, "\""], ]); }); this.emitTable(table); }); } - protected emitUnion(u: UnionType, unionName: Name): void { + protected emitUnion (u: UnionType, unionName: Name): void { const isMaybeWithSingleType = nullableFromUnion(u); if (isMaybeWithSingleType !== null) { @@ -220,7 +227,7 @@ export class PikeRenderer extends ConvenienceRenderer { types.map(r => r.map(sl => this.sourcelikeToString(sl))).join("|"), " ", unionName, - ";" + ";", ]); this.ensureBlankLine(); this.emitBlock([unionName, " ", unionName, "_from_JSON(mixed json)"], () => { @@ -228,17 +235,17 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitBlock(line: Sourcelike, f: () => void, opening: Sourcelike = " {", closing: Sourcelike = "}"): void { + private emitBlock (line: Sourcelike, f: () => void, opening: Sourcelike = " {", closing: Sourcelike = "}"): void { this.emitLine(line, opening); this.indent(f); this.emitLine(closing); } - private emitMappingBlock(line: Sourcelike, f: () => void): void { + private emitMappingBlock (line: Sourcelike, f: () => void): void { this.emitBlock(line, f, "([", "]);"); } - private emitClassMembers(c: ClassType): void { + private emitClassMembers (c: ClassType): void { let table: Sourcelike[][] = []; this.forEachClassProperty(c, "none", (name, jsonName, p) => { const pikeType = this.sourceFor(p.type).source; @@ -246,13 +253,13 @@ export class PikeRenderer extends ConvenienceRenderer { table.push([ [pikeType, " "], [name, "; "], - ['// json: "', jsonName, '"'] + ["// json: \"", jsonName, "\""], ]); }); this.emitTable(table); } - private emitInformationComment() { + private emitInformationComment () { this.emitCommentLines( [ "This source has been automatically generated by quicktype.", @@ -267,17 +274,17 @@ export class PikeRenderer extends ConvenienceRenderer { "It will return an instance of .", "Bear in mind that these functions have unexpected behavior,", "and will likely throw an error, if the JSON string does not", - "match the expected interface, even if the JSON itself is valid." + "match the expected interface, even if the JSON itself is valid.", ], - { lineStart: "// " } + { lineStart: "// " }, ); } - private emitTopLevelTypedef(t: Type, name: Name) { + private emitTopLevelTypedef (t: Type, name: Name) { this.emitLine("typedef ", this.sourceFor(t).source, " ", name, ";"); } - private emitTopLevelConverter(t: Type, name: Name) { + private emitTopLevelConverter (t: Type, name: Name) { this.emitBlock([name, " ", name, "_from_JSON(mixed json)"], () => { if (t instanceof PrimitiveType) { this.emitLine(["return json;"]); @@ -298,11 +305,11 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitEncodingFunction(c: ClassType) { + private emitEncodingFunction (c: ClassType) { this.emitBlock(["string encode_json()"], () => { this.emitMappingBlock(["mapping(string:mixed) json = "], () => { this.forEachClassProperty(c, "none", (name, jsonName) => { - this.emitLine(['"', stringEscape(jsonName), '" : ', name, ","]); + this.emitLine(["\"", stringEscape(jsonName), "\" : ", name, ","]); }); }); this.ensureBlankLine(); @@ -310,12 +317,12 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitDecodingFunction(className: Name, c: ClassType) { + private emitDecodingFunction (className: Name, c: ClassType) { this.emitBlock([className, " ", className, "_from_JSON(mixed json)"], () => { this.emitLine([className, " retval = ", className, "();"]); this.ensureBlankLine(); this.forEachClassProperty(c, "none", (name, jsonName) => { - this.emitLine(["retval.", name, ' = json["', stringEscape(jsonName), '"];']); + this.emitLine(["retval.", name, " = json[\"", stringEscape(jsonName), "\"];"]); }); this.ensureBlankLine(); this.emitLine(["return retval;"]); diff --git a/packages/quicktype-core/src/language/Python.ts b/packages/quicktype-core/src/language/Python.ts index bce7db095..91cb653e4 100644 --- a/packages/quicktype-core/src/language/Python.ts +++ b/packages/quicktype-core/src/language/Python.ts @@ -1,18 +1,23 @@ import { TargetLanguage } from "../TargetLanguage"; -import { StringTypeMapping } from "../TypeBuilder"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { + type TransformedStringTypeKind, + type PrimitiveStringTypeKind, + type Type, + type ClassProperty, +} from "../Type"; import { - TransformedStringTypeKind, - PrimitiveStringTypeKind, - Type, EnumType, ClassType, UnionType, - ClassProperty } from "../Type"; -import { RenderContext } from "../Renderer"; -import { Option, getOptionValues, OptionValues, EnumOption, BooleanOption } from "../RendererOptions"; -import { ConvenienceRenderer, ForbiddenWordsInfo, topLevelNameOrder } from "../ConvenienceRenderer"; -import { Namer, funPrefixNamer, Name, DependencyName } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { getOptionValues, EnumOption, BooleanOption } from "../RendererOptions"; +import { type ForbiddenWordsInfo} from "../ConvenienceRenderer"; +import { ConvenienceRenderer, topLevelNameOrder } from "../ConvenienceRenderer"; +import { type Namer, type Name} from "../Naming"; +import { funPrefixNamer, DependencyName } from "../Naming"; import { splitIntoWords, combineWords, @@ -21,15 +26,17 @@ import { allUpperWordStyle, allLowerWordStyle, stringEscape, - originalWord + originalWord, } from "../support/Strings"; import { assertNever, panic, defined } from "../support/Support"; -import { Sourcelike, MultiWord, multiWord, singleWord, parenIfNeeded, modifySource } from "../Source"; +import { type Sourcelike, type MultiWord} from "../Source"; +import { multiWord, singleWord, parenIfNeeded, modifySource } from "../Source"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; +import { + type Transformer} from "../Transformers"; import { followTargetType, transformationForType, - Transformer, DecodingChoiceTransformer, ChoiceTransformer, DecodingTransformer, @@ -37,7 +44,7 @@ import { ParseStringTransformer, UnionMemberMatchTransformer, StringifyTransformer, - EncodingTransformer + EncodingTransformer, } from "../Transformers"; import { arrayIntercalate, @@ -45,7 +52,7 @@ import { mapUpdateInto, iterableSome, mapSortBy, - iterableFirst + iterableFirst, } from "collection-utils"; import unicode from "unicode-properties"; @@ -64,7 +71,7 @@ const forbiddenTypeNames = [ "Type", "TypeVar", "T", - "EnumT" + "EnumT", ]; const forbiddenPropertyNames = [ "and", @@ -106,13 +113,13 @@ const forbiddenPropertyNames = [ "try", "while", "with", - "yield" + "yield", ]; -export type PythonFeatures = { - typeHints: boolean; +export interface PythonFeatures { dataClasses: boolean; -}; + typeHints: boolean; +} export const pythonOptions = { features: new EnumOption( @@ -121,20 +128,20 @@ export const pythonOptions = { [ ["3.5", { typeHints: false, dataClasses: false }], ["3.6", { typeHints: true, dataClasses: false }], - ["3.7", { typeHints: true, dataClasses: true }] + ["3.7", { typeHints: true, dataClasses: true }], ], - "3.6" + "3.6", ), justTypes: new BooleanOption("just-types", "Classes only", false), - nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be Pythonic", true) + nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be Pythonic", true), }; export class PythonTargetLanguage extends TargetLanguage { - protected getOptions(): Option[] { + protected getOptions (): Array> { return [pythonOptions.features, pythonOptions.justTypes, pythonOptions.nicePropertyNames]; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); @@ -146,22 +153,23 @@ export class PythonTargetLanguage extends TargetLanguage { return mapping; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return false; } - needsTransformerForType(t: Type): boolean { + needsTransformerForType (t: Type): boolean { if (t instanceof UnionType) { return iterableSome(t.members, m => this.needsTransformerForType(m)); } + return t.kind === "integer-string" || t.kind === "bool-string"; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): PythonRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): PythonRenderer { const options = getOptionValues(pythonOptions, untypedOptionValues); if (options.justTypes) { return new PythonRenderer(this, renderContext, options); @@ -171,41 +179,43 @@ export class PythonTargetLanguage extends TargetLanguage { } } -function isNormalizedStartCharacter3(utf16Unit: number): boolean { +function isNormalizedStartCharacter3 (utf16Unit: number): boolean { // FIXME: add Other_ID_Start - https://docs.python.org/3/reference/lexical_analysis.html#identifiers const category: string = unicode.getCategory(utf16Unit); - return ["Lu", "Ll", "Lt", "Lm", "Lo", "Nl"].indexOf(category) >= 0; + return ["Lu", "Ll", "Lt", "Lm", "Lo", "Nl"].includes(category); } -function isNormalizedPartCharacter3(utf16Unit: number): boolean { +function isNormalizedPartCharacter3 (utf16Unit: number): boolean { // FIXME: add Other_ID_Continue - https://docs.python.org/3/reference/lexical_analysis.html#identifiers if (isNormalizedStartCharacter3(utf16Unit)) return true; const category: string = unicode.getCategory(utf16Unit); - return ["Mn", "Mc", "Nd", "Pc"].indexOf(category) >= 0; + return ["Mn", "Mc", "Nd", "Pc"].includes(category); } -function isStartCharacter3(utf16Unit: number): boolean { +function isStartCharacter3 (utf16Unit: number): boolean { const s = String.fromCharCode(utf16Unit).normalize("NFKC"); const l = s.length; if (l === 0 || !isNormalizedStartCharacter3(s.charCodeAt(0))) return false; for (let i = 1; i < l; i++) { if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; } + return true; } -function isPartCharacter3(utf16Unit: number): boolean { +function isPartCharacter3 (utf16Unit: number): boolean { const s = String.fromCharCode(utf16Unit).normalize("NFKC"); const l = s.length; for (let i = 0; i < l; i++) { if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; } + return true; } const legalizeName3 = utf16LegalizeCharacters(isPartCharacter3); -function classNameStyle(original: string): string { +function classNameStyle (original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -215,18 +225,19 @@ function classNameStyle(original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter3 + isStartCharacter3, ); } -function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean) { +function getWordStyle (uppercase: boolean, forceSnakeNameStyle: boolean) { if (!forceSnakeNameStyle) { return originalWord; } + return uppercase ? allUpperWordStyle : allLowerWordStyle; } -function snakeNameStyle(original: string, uppercase: boolean, forceSnakeNameStyle: boolean): string { +function snakeNameStyle (original: string, uppercase: boolean, forceSnakeNameStyle: boolean): string { const wordStyle = getWordStyle(uppercase, forceSnakeNameStyle); const separator = forceSnakeNameStyle ? "_" : ""; const words = splitIntoWords(original); @@ -235,104 +246,106 @@ function snakeNameStyle(original: string, uppercase: boolean, forceSnakeNameStyl export class PythonRenderer extends ConvenienceRenderer { private readonly imports: Map> = new Map(); + private readonly declaredTypes: Set = new Set(); - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly pyOptions: OptionValues + protected readonly pyOptions: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return forbiddenTypeNames; } - protected forbiddenForObjectProperties(_: ClassType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_: ClassType, _classNamed: Name): ForbiddenWordsInfo { return { names: forbiddenPropertyNames, includeGlobalForbidden: false }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("type", classNameStyle); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return funPrefixNamer("property", s => snakeNameStyle(s, false, this.pyOptions.nicePropertyNames)); } - protected makeUnionMemberNamer(): null { + protected makeUnionMemberNamer (): null { return null; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("enum-case", s => snakeNameStyle(s, true, this.pyOptions.nicePropertyNames)); } - protected get commentLineStart(): string { + protected get commentLineStart (): string { return "# "; } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { if (lines.length === 1) { const docstring = modifySource(content => { - if (content.endsWith('"')) { - return content.slice(0, -1) + '\\"'; + if (content.endsWith("\"")) { + return content.slice(0, -1) + "\\\""; } return content; }, lines[0]); - this.emitComments([{ customLines: [docstring], lineStart: '"""', lineEnd: '"""' }]); + this.emitComments([{ customLines: [docstring], lineStart: "\"\"\"", lineEnd: "\"\"\"" }]); } else { this.emitCommentLines(lines, { - firstLineStart: '"""', + firstLineStart: "\"\"\"", lineStart: "", - afterComment: '"""' + afterComment: "\"\"\"", }); } } - protected get needsTypeDeclarationBeforeUse(): boolean { + protected get needsTypeDeclarationBeforeUse (): boolean { return true; } - protected canBeForwardDeclared(t: Type): boolean { + protected canBeForwardDeclared (t: Type): boolean { const kind = t.kind; return kind === "class" || kind === "enum"; } - protected emitBlock(line: Sourcelike, f: () => void): void { + protected emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line); this.indent(f); } - protected string(s: string): Sourcelike { - const openQuote = '"'; - return [openQuote, stringEscape(s), '"']; + protected string (s: string): Sourcelike { + const openQuote = "\""; + return [openQuote, stringEscape(s), "\""]; } - protected withImport(module: string, name: string): Sourcelike { + protected withImport (module: string, name: string): Sourcelike { if (this.pyOptions.features.typeHints || module !== "typing") { // FIXME: This is ugly. We should rather not generate that import in the first // place, but right now we just make the type source and then throw it away. It's // not a performance issue, so it's fine, I just bemoan this special case, and // potential others down the road. - mapUpdateInto(this.imports, module, s => (s ? setUnionInto(s, [name]) : new Set([name]))); + mapUpdateInto(this.imports, module, s => s ? setUnionInto(s, [name]) : new Set([name])); } + return name; } - protected withTyping(name: string): Sourcelike { + protected withTyping (name: string): Sourcelike { return this.withImport("typing", name); } - protected namedType(t: Type): Sourcelike { + protected namedType (t: Type): Sourcelike { const name = this.nameForNamedType(t); if (this.declaredTypes.has(t)) return name; return ["'", name, "'"]; } - protected pythonType(t: Type, _isRootTypeDef = false): Sourcelike { + protected pythonType (t: Type, _isRootTypeDef = false): Sourcelike { const actualType = followTargetType(t); return matchType( @@ -367,7 +380,7 @@ export class PythonRenderer extends ConvenienceRenderer { "[Union[", arrayIntercalate(", ", memberTypes), "]]", - ...rest + ...rest, ]; } else { return [this.withTyping("Optional"), "[", defined(iterableFirst(memberTypes)), "]", ...rest]; @@ -380,21 +393,25 @@ export class PythonRenderer extends ConvenienceRenderer { if (transformedStringType.kind === "date-time") { return this.withImport("datetime", "datetime"); } + if (transformedStringType.kind === "uuid") { return this.withImport("uuid", "UUID"); } + return panic(`Transformed type ${transformedStringType.kind} not supported`); - } + }, ); } - protected declarationLine(t: Type): Sourcelike { + protected declarationLine (t: Type): Sourcelike { if (t instanceof ClassType) { return ["class ", this.nameForNamedType(t), ":"]; } + if (t instanceof EnumType) { return ["class ", this.nameForNamedType(t), "(", this.withImport("enum", "Enum"), "):"]; } + return panic(`Can't declare type ${t.kind}`); } @@ -406,7 +423,7 @@ export class PythonRenderer extends ConvenienceRenderer { this.declaredTypes.add(t); } - protected emitClassMembers(t: ClassType): void { + protected emitClassMembers (t: ClassType): void { if (this.pyOptions.features.dataClasses) return; const args: Sourcelike[] = []; @@ -423,42 +440,44 @@ export class PythonRenderer extends ConvenienceRenderer { this.emitLine("self.", name, " = ", name); }); } - } + }, ); } - protected typeHint(...sl: Sourcelike[]): Sourcelike { + protected typeHint (...sl: Sourcelike[]): Sourcelike { if (this.pyOptions.features.typeHints) { return sl; } + return []; } - protected typingDecl(name: Sourcelike, type: string): Sourcelike { + protected typingDecl (name: Sourcelike, type: string): Sourcelike { return [name, this.typeHint(": ", this.withTyping(type))]; } - protected typingReturn(type: string): Sourcelike { + protected typingReturn (type: string): Sourcelike { return this.typeHint(" -> ", this.withTyping(type)); } - protected sortClassProperties( + protected sortClassProperties ( properties: ReadonlyMap, - propertyNames: ReadonlyMap + propertyNames: ReadonlyMap, ): ReadonlyMap { if (this.pyOptions.features.dataClasses) { return mapSortBy(properties, (p: ClassProperty) => { - return (p.type instanceof UnionType && nullableFromUnion(p.type) != null) || p.isOptional ? 1 : 0; + return p.type instanceof UnionType && nullableFromUnion(p.type) != null || p.isOptional ? 1 : 0; }); } else { return super.sortClassProperties(properties, propertyNames); } } - protected emitClass(t: ClassType): void { + protected emitClass (t: ClassType): void { if (this.pyOptions.features.dataClasses) { this.emitLine("@", this.withImport("dataclasses", "dataclass")); } + this.declareType(t, () => { if (this.pyOptions.features.typeHints) { if (t.getProperties().size === 0) { @@ -469,13 +488,15 @@ export class PythonRenderer extends ConvenienceRenderer { this.emitDescription(this.descriptionForClassProperty(t, jsonName)); }); } + this.ensureBlankLine(); } + this.emitClassMembers(t); }); } - protected emitEnum(t: EnumType): void { + protected emitEnum (t: EnumType): void { this.declareType(t, () => { this.forEachEnumCase(t, "none", (name, jsonName) => { this.emitLine([name, " = ", this.string(jsonName)]); @@ -483,21 +504,21 @@ export class PythonRenderer extends ConvenienceRenderer { }); } - protected emitImports(): void { + protected emitImports (): void { this.imports.forEach((names, module) => { this.emitLine("from ", module, " import ", Array.from(names).join(", ")); }); } - protected emitSupportCode(): void { + protected emitSupportCode (): void { return; } - protected emitClosingCode(): void { + protected emitClosingCode (): void { return; } - protected emitSourceStructure(_givenOutputFilename: string): void { + protected emitSourceStructure (_givenOutputFilename: string): void { const declarationLines = this.gatherSource(() => { this.forEachNamedType( ["interposing", 2], @@ -505,7 +526,7 @@ export class PythonRenderer extends ConvenienceRenderer { e => this.emitEnum(e), _u => { return; - } + }, ); }); @@ -515,6 +536,7 @@ export class PythonRenderer extends ConvenienceRenderer { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } + this.ensureBlankLine(); this.emitImports(); this.ensureBlankLine(2); @@ -542,10 +564,10 @@ export type ConverterFunction = | "from-stringified-bool" | "is-type"; -type TopLevelConverterNames = { +interface TopLevelConverterNames { fromDict: Name; toDict: Name; -}; +} // A value or a lambda. All four combinations are valid: // @@ -553,10 +575,10 @@ type TopLevelConverterNames = { // * `lambda` only: a lambda given by `lambda` // * `value` only: a value given by `value` // * neither: the identity function, i.e. `lambda x: x` -export type ValueOrLambda = { - value: Sourcelike | undefined; +export interface ValueOrLambda { lambda?: MultiWord; -}; + value: Sourcelike | undefined; +} // Return the result of composing `input` and `f`. `input` can be a // value or a lambda, but `f` must be a lambda or a TypeScript function @@ -564,18 +586,20 @@ export type ValueOrLambda = { // // * If `input` is a value, the result is `f(input)`. // * If `input` is a lambda, the result is `lambda x: f(input(x))` -function compose(input: ValueOrLambda, f: (arg: Sourcelike) => Sourcelike): ValueOrLambda; -function compose(input: ValueOrLambda, f: ValueOrLambda): ValueOrLambda; -function compose(input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => Sourcelike)): ValueOrLambda { +function compose (input: ValueOrLambda, f: (arg: Sourcelike) => Sourcelike): ValueOrLambda; +function compose (input: ValueOrLambda, f: ValueOrLambda): ValueOrLambda; +function compose (input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => Sourcelike)): ValueOrLambda { if (typeof f === "function") { if (input.value !== undefined) { // `input` is a value, so just apply `f` to its source form. return { value: f(makeValue(input)) }; } + if (input.lambda !== undefined) { // `input` is a lambda, so build `lambda x: f(input(x))`. return { lambda: multiWord(" ", "lambda x:", f([parenIfNeeded(input.lambda), "(x)"])), value: undefined }; } + // `input` is the identify function, so the composition is `lambda x: f(x)`. return { lambda: multiWord(" ", "lambda x:", f("x")), value: undefined }; } @@ -583,6 +607,7 @@ function compose(input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => if (f.value !== undefined) { return panic("Cannot compose into a value"); } + if (f.lambda === undefined) { // `f` is the identity function, so the result is just `input`. return input; @@ -594,10 +619,11 @@ function compose(input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => // `input` is the identity function, so the result is just `f`. return f; } + // `input` is a lambda, so the result is `lambda x: f(input(x))`. return { lambda: multiWord("", "lambda x: ", parenIfNeeded(f.lambda), "(", parenIfNeeded(input.lambda), "(x))"), - value: undefined + value: undefined, }; } @@ -609,48 +635,58 @@ const identity: ValueOrLambda = { value: undefined }; // If `vol` is a lambda, return it in its source form. If it's // a value, return a `lambda` that returns the value. -function makeLambda(vol: ValueOrLambda): MultiWord { +function makeLambda (vol: ValueOrLambda): MultiWord { if (vol.lambda !== undefined) { if (vol.value === undefined) { return vol.lambda; } + return multiWord("", "lambda x: ", parenIfNeeded(vol.lambda), "(", vol.value, ")"); } else if (vol.value !== undefined) { return multiWord(" ", "lambda x:", vol.value); } + return multiWord(" ", "lambda x:", "x"); } // If `vol` is a value, return the value in its source form. // Calling this with `vol` being a lambda is not allowed. -function makeValue(vol: ValueOrLambda): Sourcelike { +function makeValue (vol: ValueOrLambda): Sourcelike { if (vol.value === undefined) { return panic("Cannot make value from lambda without value"); } + if (vol.lambda !== undefined) { return [parenIfNeeded(vol.lambda), "(", vol.value, ")"]; } + return vol.value; } export class JSONPythonRenderer extends PythonRenderer { private readonly _deserializerFunctions = new Set(); + private readonly _converterNamer = funPrefixNamer("converter", s => - snakeNameStyle(s, false, this.pyOptions.nicePropertyNames) + snakeNameStyle(s, false, this.pyOptions.nicePropertyNames), ); + private readonly _topLevelConverterNames = new Map(); + private _haveTypeVar = false; + private _haveEnumTypeVar = false; + private _haveDateutil = false; - protected emitTypeVar(tvar: string, constraints: Sourcelike): void { + protected emitTypeVar (tvar: string, constraints: Sourcelike): void { if (!this.pyOptions.features.typeHints) { return; } + this.emitLine(tvar, " = ", this.withTyping("TypeVar"), "(", this.string(tvar), constraints, ")"); } - protected typeVar(): string { + protected typeVar (): string { this._haveTypeVar = true; // FIXME: This is ugly, but the code that requires the type variables, in // `emitImports` actually runs after imports have been imported. The proper @@ -662,7 +698,7 @@ export class JSONPythonRenderer extends PythonRenderer { return "T"; } - protected enumTypeVar(): string { + protected enumTypeVar (): string { this._haveEnumTypeVar = true; // See the comment above. this.withTyping("TypeVar"); @@ -670,14 +706,15 @@ export class JSONPythonRenderer extends PythonRenderer { return "EnumT"; } - protected cast(type: Sourcelike, v: Sourcelike): Sourcelike { + protected cast (type: Sourcelike, v: Sourcelike): Sourcelike { if (!this.pyOptions.features.typeHints) { return v; } + return [this.withTyping("cast"), "(", type, ", ", v, ")"]; } - protected emitNoneConverter(): void { + protected emitNoneConverter (): void { // FIXME: We can't return the None type here because mypy thinks that means // We're not returning any value, when we're actually returning `None`. this.emitBlock( @@ -685,39 +722,39 @@ export class JSONPythonRenderer extends PythonRenderer { () => { this.emitLine("assert x is None"); this.emitLine("return x"); - } + }, ); } - protected emitBoolConverter(): void { + protected emitBoolConverter (): void { this.emitBlock(["def from_bool(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> bool"), ":"], () => { this.emitLine("assert isinstance(x, bool)"); this.emitLine("return x"); }); } - protected emitIntConverter(): void { + protected emitIntConverter (): void { this.emitBlock(["def from_int(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> int"), ":"], () => { this.emitLine("assert isinstance(x, int) and not isinstance(x, bool)"); this.emitLine("return x"); }); } - protected emitFromFloatConverter(): void { + protected emitFromFloatConverter (): void { this.emitBlock(["def from_float(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> float"), ":"], () => { this.emitLine("assert isinstance(x, (float, int)) and not isinstance(x, bool)"); this.emitLine("return float(x)"); }); } - protected emitToFloatConverter(): void { + protected emitToFloatConverter (): void { this.emitBlock(["def to_float(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> float"), ":"], () => { this.emitLine("assert isinstance(x, float)"); this.emitLine("return x"); }); } - protected emitStrConverter(): void { + protected emitStrConverter (): void { this.emitBlock(["def from_str(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> str"), ":"], () => { const strType = "str"; this.emitLine("assert isinstance(x, ", strType, ")"); @@ -725,7 +762,7 @@ export class JSONPythonRenderer extends PythonRenderer { }); } - protected emitToEnumConverter(): void { + protected emitToEnumConverter (): void { const tvar = this.enumTypeVar(); this.emitBlock( [ @@ -735,16 +772,16 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", tvar), - ":" + ":", ], () => { this.emitLine("assert isinstance(x, c)"); this.emitLine("return x.value"); - } + }, ); } - protected emitListConverter(): void { + protected emitListConverter (): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -754,16 +791,16 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withTyping("List"), "[", tvar, "]"), - ":" + ":", ], () => { this.emitLine("assert isinstance(x, list)"); this.emitLine("return [f(y) for y in x]"); - } + }, ); } - protected emitToClassConverter(): void { + protected emitToClassConverter (): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -773,16 +810,16 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> dict"), - ":" + ":", ], () => { this.emitLine("assert isinstance(x, c)"); this.emitLine("return ", this.cast(this.withTyping("Any"), "x"), ".to_dict()"); - } + }, ); } - protected emitDictConverter(): void { + protected emitDictConverter (): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -792,18 +829,18 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withTyping("Dict"), "[str, ", tvar, "]"), - ":" + ":", ], () => { this.emitLine("assert isinstance(x, dict)"); this.emitLine("return { k: f(v) for (k, v) in x.items() }"); - } + }, ); } // This is not easily idiomatically typeable in Python. See // https://stackoverflow.com/questions/51066468/computed-types-in-mypy/51084497 - protected emitUnionConverter(): void { + protected emitUnionConverter (): void { this.emitMultiline(`def from_union(fs, x): for f in fs: try: @@ -813,34 +850,34 @@ export class JSONPythonRenderer extends PythonRenderer { assert False`); } - protected emitFromDatetimeConverter(): void { + protected emitFromDatetimeConverter (): void { this.emitBlock( [ "def from_datetime(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withImport("datetime", "datetime")), - ":" + ":", ], () => { this._haveDateutil = true; this.emitLine("return dateutil.parser.parse(x)"); - } + }, ); } - protected emitFromStringifiedBoolConverter(): void { + protected emitFromStringifiedBoolConverter (): void { this.emitBlock( ["def from_stringified_bool(x", this.typeHint(": str"), ")", this.typeHint(" -> bool"), ":"], () => { - this.emitBlock('if x == "true":', () => this.emitLine("return True")); - this.emitBlock('if x == "false":', () => this.emitLine("return False")); + this.emitBlock("if x == \"true\":", () => this.emitLine("return True")); + this.emitBlock("if x == \"false\":", () => this.emitLine("return False")); this.emitLine("assert False"); - } + }, ); } - protected emitIsTypeConverter(): void { + protected emitIsTypeConverter (): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -850,52 +887,66 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", tvar), - ":" + ":", ], () => { this.emitLine("assert isinstance(x, t)"); this.emitLine("return x"); - } + }, ); } - protected emitConverter(cf: ConverterFunction): void { + protected emitConverter (cf: ConverterFunction): void { switch (cf) { case "none": - return this.emitNoneConverter(); + { this.emitNoneConverter(); return; } + case "bool": - return this.emitBoolConverter(); + { this.emitBoolConverter(); return; } + case "int": - return this.emitIntConverter(); + { this.emitIntConverter(); return; } + case "from-float": - return this.emitFromFloatConverter(); + { this.emitFromFloatConverter(); return; } + case "to-float": - return this.emitToFloatConverter(); + { this.emitToFloatConverter(); return; } + case "str": - return this.emitStrConverter(); + { this.emitStrConverter(); return; } + case "to-enum": - return this.emitToEnumConverter(); + { this.emitToEnumConverter(); return; } + case "list": - return this.emitListConverter(); + { this.emitListConverter(); return; } + case "to-class": - return this.emitToClassConverter(); + { this.emitToClassConverter(); return; } + case "dict": - return this.emitDictConverter(); + { this.emitDictConverter(); return; } + case "union": - return this.emitUnionConverter(); + { this.emitUnionConverter(); return; } + case "from-datetime": - return this.emitFromDatetimeConverter(); + { this.emitFromDatetimeConverter(); return; } + case "from-stringified-bool": - return this.emitFromStringifiedBoolConverter(); + { this.emitFromStringifiedBoolConverter(); return; } + case "is-type": - return this.emitIsTypeConverter(); + { this.emitIsTypeConverter(); return; } + default: return assertNever(cf); } } // Return the name of the Python converter function `cf`. - protected conv(cf: ConverterFunction): Sourcelike { + protected conv (cf: ConverterFunction): Sourcelike { this._deserializerFunctions.add(cf); const name = cf.replace(/-/g, "_"); if (cf.startsWith("from-") || cf.startsWith("to-") || cf.startsWith("is-")) return name; @@ -903,11 +954,11 @@ export class JSONPythonRenderer extends PythonRenderer { } // Applies the converter function to `arg` - protected convFn(cf: ConverterFunction, arg: ValueOrLambda): ValueOrLambda { + protected convFn (cf: ConverterFunction, arg: ValueOrLambda): ValueOrLambda { return compose(arg, { lambda: singleWord(this.conv(cf)), value: undefined }); } - protected typeObject(t: Type): Sourcelike { + protected typeObject (t: Type): Sourcelike { const s = matchType( t, _anyType => undefined, @@ -925,23 +976,27 @@ export class JSONPythonRenderer extends PythonRenderer { if (transformedStringType.kind === "date-time") { return this.withImport("datetime", "datetime"); } + if (transformedStringType.kind === "uuid") { return this.withImport("uuid", "UUID"); } + return undefined; - } + }, ); if (s === undefined) { return panic(`No type object for ${t.kind}`); } + return s; } - protected transformer(inputTransformer: ValueOrLambda, xfer: Transformer, targetType: Type): ValueOrLambda { + protected transformer (inputTransformer: ValueOrLambda, xfer: Transformer, targetType: Type): ValueOrLambda { const consume = (consumer: Transformer | undefined, vol: ValueOrLambda) => { if (consumer === undefined) { return vol; } + return this.transformer(vol, consumer, targetType); }; @@ -957,7 +1012,7 @@ export class JSONPythonRenderer extends PythonRenderer { arrayIntercalate(", ", lambdas), "], ", v, - ")" + ")", ]); } else if (xfer instanceof DecodingTransformer) { const consumer = xfer.consumer; @@ -994,6 +1049,7 @@ export class JSONPythonRenderer extends PythonRenderer { default: return panic(`Parsing of ${immediateTargetType.kind} in a transformer is not supported`); } + return consume(consumer, vol); } else if (xfer instanceof StringifyTransformer) { const consumer = xfer.consumer; @@ -1017,6 +1073,7 @@ export class JSONPythonRenderer extends PythonRenderer { default: return panic(`Parsing of ${xfer.sourceType.kind} in a transformer is not supported`); } + return consume(consumer, vol); } else { return panic(`Transformer ${xfer.kind} is not supported`); @@ -1026,11 +1083,12 @@ export class JSONPythonRenderer extends PythonRenderer { // Returns the code to deserialize `value` as type `t`. If `t` has // an associated transformer, the code for that transformer is // returned. - protected deserializer(value: ValueOrLambda, t: Type): ValueOrLambda { + protected deserializer (value: ValueOrLambda, t: Type): ValueOrLambda { const xf = transformationForType(t); if (xf !== undefined) { return this.transformer(value, xf.transformer, xf.targetType); } + return matchType( t, _anyType => value, @@ -1046,12 +1104,12 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.deserializer(identity, arrayType.items)).source, ", ", v, - ")" + ")", ]), classType => compose(value, { lambda: singleWord(this.nameForNamedType(classType), ".from_dict"), - value: undefined + value: undefined, }), mapType => compose(value, v => [ @@ -1060,13 +1118,13 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.deserializer(identity, mapType.values)).source, ", ", v, - ")" + ")", ]), enumType => compose(value, { lambda: singleWord(this.nameForNamedType(enumType)), value: undefined }), unionType => { // FIXME: handle via transformers const deserializers = Array.from(unionType.members).map( - m => makeLambda(this.deserializer(identity, m)).source + m => makeLambda(this.deserializer(identity, m)).source, ); return compose(value, v => [ this.conv("union"), @@ -1074,7 +1132,7 @@ export class JSONPythonRenderer extends PythonRenderer { arrayIntercalate(", ", deserializers), "], ", v, - ")" + ")", ]); }, transformedStringType => { @@ -1082,20 +1140,23 @@ export class JSONPythonRenderer extends PythonRenderer { if (transformedStringType.kind === "date-time") { return this.convFn("from-datetime", value); } + if (transformedStringType.kind === "uuid") { return compose(value, v => [this.withImport("uuid", "UUID"), "(", v, ")"]); } + return panic(`Transformed type ${transformedStringType.kind} not supported`); - } + }, ); } - protected serializer(value: ValueOrLambda, t: Type): ValueOrLambda { + protected serializer (value: ValueOrLambda, t: Type): ValueOrLambda { const xf = transformationForType(t); if (xf !== undefined) { const reverse = xf.reverse; return this.transformer(value, reverse.transformer, reverse.targetType); } + return matchType( t, _anyType => value, @@ -1111,7 +1172,7 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.serializer(identity, arrayType.items)).source, ", ", v, - ")" + ")", ]), classType => compose(value, v => [this.conv("to-class"), "(", this.nameForNamedType(classType), ", ", v, ")"]), @@ -1122,12 +1183,12 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.serializer(identity, mapType.values)).source, ", ", v, - ")" + ")", ]), enumType => compose(value, v => [this.conv("to-enum"), "(", this.nameForNamedType(enumType), ", ", v, ")"]), unionType => { const serializers = Array.from(unionType.members).map( - m => makeLambda(this.serializer(identity, m)).source + m => makeLambda(this.serializer(identity, m)).source, ); return compose(value, v => [ this.conv("union"), @@ -1135,22 +1196,24 @@ export class JSONPythonRenderer extends PythonRenderer { arrayIntercalate(", ", serializers), "], ", v, - ")" + ")", ]); }, transformedStringType => { if (transformedStringType.kind === "date-time") { return compose(value, v => [v, ".isoformat()"]); } + if (transformedStringType.kind === "uuid") { return compose(value, v => ["str(", v, ")"]); } + return panic(`Transformed type ${transformedStringType.kind} not supported`); - } + }, ); } - protected emitClassMembers(t: ClassType): void { + protected emitClassMembers (t: ClassType): void { super.emitClassMembers(t); this.ensureBlankLine(); @@ -1168,7 +1231,7 @@ export class JSONPythonRenderer extends PythonRenderer { args.push(name); }); this.emitLine("return ", className, "(", arrayIntercalate(", ", args), ")"); - } + }, ); this.ensureBlankLine(); @@ -1182,7 +1245,7 @@ export class JSONPythonRenderer extends PythonRenderer { "result[", this.string(jsonName), "] = ", - makeValue(this.serializer(property, cp.type)) + makeValue(this.serializer(property, cp.type)), ); }); } else { @@ -1190,7 +1253,7 @@ export class JSONPythonRenderer extends PythonRenderer { "result[", this.string(jsonName), "] = ", - makeValue(this.serializer(property, cp.type)) + makeValue(this.serializer(property, cp.type)), ); } }); @@ -1198,7 +1261,7 @@ export class JSONPythonRenderer extends PythonRenderer { }); } - protected emitImports(): void { + protected emitImports (): void { super.emitImports(); if (this._haveDateutil) { this.emitLine("import dateutil.parser"); @@ -1210,46 +1273,48 @@ export class JSONPythonRenderer extends PythonRenderer { if (this._haveTypeVar) { this.emitTypeVar(this.typeVar(), []); } + if (this._haveEnumTypeVar) { this.emitTypeVar(this.enumTypeVar(), [", bound=", this.withImport("enum", "Enum")]); } } - protected emitSupportCode(): void { + protected emitSupportCode (): void { const map = Array.from(this._deserializerFunctions).map(f => [f, f] as [ConverterFunction, ConverterFunction]); this.forEachWithBlankLines(map, ["interposing", 2], cf => { this.emitConverter(cf); }); } - protected makeTopLevelDependencyNames(_t: Type, topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames (_t: Type, topLevelName: Name): DependencyName[] { const fromDict = new DependencyName( this._converterNamer, topLevelNameOrder, - l => `${l(topLevelName)}_from_dict` + l => `${l(topLevelName)}_from_dict`, ); const toDict = new DependencyName(this._converterNamer, topLevelNameOrder, l => `${l(topLevelName)}_to_dict`); this._topLevelConverterNames.set(topLevelName, { fromDict, toDict }); return [fromDict, toDict]; } - protected emitDefaultLeadingComments(): void { + protected emitDefaultLeadingComments (): void { this.ensureBlankLine(); if (this._haveDateutil) { this.emitCommentLines([ "This code parses date/times, so please", "", " pip install python-dateutil", - "" + "", ]); } + this.emitCommentLines([ "To use this code, make sure you", "", " import json", "", "and then, to convert JSON from a string, do", - "" + "", ]); this.forEachTopLevel("none", (_, name) => { const { fromDict } = defined(this._topLevelConverterNames.get(name)); @@ -1257,7 +1322,7 @@ export class JSONPythonRenderer extends PythonRenderer { }); } - protected emitClosingCode(): void { + protected emitClosingCode (): void { this.forEachTopLevel(["interposing", 2], (t, name) => { const { fromDict, toDict } = defined(this._topLevelConverterNames.get(name)); const pythonType = this.pythonType(t); @@ -1265,14 +1330,14 @@ export class JSONPythonRenderer extends PythonRenderer { ["def ", fromDict, "(", this.typingDecl("s", "Any"), ")", this.typeHint(" -> ", pythonType), ":"], () => { this.emitLine("return ", makeValue(this.deserializer({ value: "s" }, t))); - } + }, ); this.ensureBlankLine(2); this.emitBlock( ["def ", toDict, "(x", this.typeHint(": ", pythonType), ")", this.typingReturn("Any"), ":"], () => { this.emitLine("return ", makeValue(this.serializer({ value: "x" }, t))); - } + }, ); }); } diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust.ts index 56b464161..b09b1dc7f 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust.ts @@ -1,7 +1,8 @@ import { mapFirst } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { legalizeCharacters, splitIntoWords, @@ -14,16 +15,20 @@ import { escapeNonPrintableMapper, isPrintable, isAscii, - isLetterOrUnderscore + isLetterOrUnderscore, } from "../support/Strings"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { UnionType, Type, ClassType, EnumType } from "../Type"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Type, type ClassType, type EnumType } from "../Type"; +import { UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { Sourcelike, maybeAnnotated } from "../Source"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { BooleanOption, EnumOption, Option, getOptionValues, OptionValues } from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { BooleanOption, EnumOption, getOptionValues } from "../RendererOptions"; import { defined } from "../support/Support"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; export enum Density { Normal, @@ -39,39 +44,39 @@ export enum Visibility { export const rustOptions = { density: new EnumOption("density", "Density", [ ["normal", Density.Normal], - ["dense", Density.Dense] + ["dense", Density.Dense], ]), visibility: new EnumOption("visibility", "Field visibility", [ ["private", Visibility.Private], ["crate", Visibility.Crate], - ["public", Visibility.Public] + ["public", Visibility.Public], ]), deriveDebug: new BooleanOption("derive-debug", "Derive Debug impl", false), deriveClone: new BooleanOption("derive-clone", "Derive Clone impl", false), derivePartialEq: new BooleanOption("derive-partial-eq", "Derive PartialEq impl", false), skipSerializingNone: new BooleanOption("skip-serializing-none", "Skip serializing empty Option fields", false), edition2018: new BooleanOption("edition-2018", "Edition 2018", true), - leadingComments: new BooleanOption("leading-comments", "Leading Comments", true) + leadingComments: new BooleanOption("leading-comments", "Leading Comments", true), }; type NameToParts = (name: string) => string[]; type PartsToName = (parts: string[]) => string; -type NamingStyle = { +interface NamingStyle { + fromParts: PartsToName; regex: RegExp; toParts: NameToParts; - fromParts: PartsToName; -}; +} const namingStyles: Record = { snake_case: { regex: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/, toParts: (name: string): string[] => name.split("_"), - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("_") + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("_"), }, SCREAMING_SNAKE_CASE: { regex: /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/, toParts: (name: string): string[] => name.split("_"), - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("_") + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("_"), }, camelCase: { regex: /^[a-z]+([A-Z0-9][a-z]*)*$/, @@ -79,48 +84,48 @@ const namingStyles: Record = { fromParts: (parts: string[]): string => parts .map((p, i) => - i === 0 ? p.toLowerCase() : p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase() + i === 0 ? p.toLowerCase() : p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase(), ) - .join("") + .join(""), }, PascalCase: { regex: /^[A-Z][a-z]*([A-Z0-9][a-z]*)*$/, toParts: (name: string): string[] => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")), fromParts: (parts: string[]): string => - parts.map(p => p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase()).join("") + parts.map(p => p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase()).join(""), }, "kebab-case": { regex: /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/, toParts: (name: string): string[] => name.split("-"), - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("-") + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("-"), }, "SCREAMING-KEBAB-CASE": { regex: /^[A-Z][A-Z0-9]*(-[A-Z0-9]+)*$/, toParts: (name: string): string[] => name.split("-"), - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("-") + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("-"), }, lowercase: { regex: /^[a-z][a-z0-9]*$/, toParts: (name: string): string[] => [name], - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("") + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join(""), }, UPPERCASE: { regex: /^[A-Z][A-Z0-9]*$/, toParts: (name: string): string[] => [name], - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("") - } + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join(""), + }, }; export class RustTargetLanguage extends TargetLanguage { - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): RustRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): RustRenderer { return new RustRenderer(this, renderContext, getOptionValues(rustOptions, untypedOptionValues)); } - constructor() { + constructor () { super("Rust", ["rust", "rs", "rustlang"], "rs"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ rustOptions.density, rustOptions.visibility, @@ -129,7 +134,7 @@ export class RustTargetLanguage extends TargetLanguage { rustOptions.derivePartialEq, rustOptions.edition2018, rustOptions.leadingComments, - rustOptions.skipSerializingNone + rustOptions.skipSerializingNone, ]; } } @@ -208,7 +213,7 @@ const keywords = [ "union", // Conflict between `std::Option` and potentially generated Option - "option" + "option", ]; const isAsciiLetterOrUnderscoreOrDigit = (codePoint: number): boolean => { @@ -229,7 +234,7 @@ const isAsciiLetterOrUnderscore = (codePoint: number): boolean => { const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); -function rustStyle(original: string, isSnakeCase: boolean): string { +function rustStyle (original: string, isSnakeCase: boolean): string { const words = splitIntoWords(original); const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; @@ -242,7 +247,7 @@ function rustStyle(original: string, isSnakeCase: boolean): string { wordStyle, wordStyle, isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore + isAsciiLetterOrUnderscore, ); return combined === "_" ? "_underscore" : combined; @@ -262,60 +267,60 @@ const standardUnicodeRustEscape = (codePoint: number): string => { const rustStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeRustEscape)); export class RustRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return camelNamingFunction; } - protected namerForObjectProperty(): Namer | null { + protected namerForObjectProperty (): Namer | null { return snakeNamingFunction; } - protected makeUnionMemberNamer(): Namer | null { + protected makeUnionMemberNamer (): Namer | null { return camelNamingFunction; } - protected makeEnumCaseNamer(): Namer | null { + protected makeEnumCaseNamer (): Namer | null { return camelNamingFunction; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected get commentLineStart(): string { + protected get commentLineStart (): string { return "/// "; } - private nullableRustType(t: Type, withIssues: boolean): Sourcelike { + private nullableRustType (t: Type, withIssues: boolean): Sourcelike { return ["Option<", this.breakCycle(t, withIssues), ">"]; } - protected isImplicitCycleBreaker(t: Type): boolean { + protected isImplicitCycleBreaker (t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } - private rustType(t: Type, withIssues = false): Sourcelike { + private rustType (t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "Option"), @@ -342,60 +347,61 @@ export class RustRenderer extends ConvenienceRenderer { : this.nameForNamedType(unionType); return hasNull !== null ? (["Option<", name, ">"] as Sourcelike) : name; - } + }, ); } - private breakCycle(t: Type, withIssues: boolean): any { + private breakCycle (t: Type, withIssues: boolean): any { const rustType = this.rustType(t, withIssues); const isCycleBreaker = this.isCycleBreakerType(t); return isCycleBreaker ? ["Box<", rustType, ">"] : rustType; } - private emitRenameAttribute( + private emitRenameAttribute ( propName: Name, jsonName: string, defaultNamingStyle: string, - preferedNamingStyle: string + preferedNamingStyle: string, ) { const escapedName = rustStringEscape(jsonName); const name = namingStyles[defaultNamingStyle].fromParts(this.sourcelikeToString(propName).split(" ")); const styledName = nameToNamingStyle(name, preferedNamingStyle); const namesDiffer = escapedName !== styledName; if (namesDiffer) { - this.emitLine('#[serde(rename = "', escapedName, '")]'); + this.emitLine("#[serde(rename = \"", escapedName, "\")]"); } } - private emitSkipSerializeNone(t: Type) { + private emitSkipSerializeNone (t: Type) { if (t instanceof UnionType) { const nullable = nullableFromUnion(t); - if (nullable !== null) this.emitLine('#[serde(skip_serializing_if = "Option::is_none")]'); + if (nullable !== null) this.emitLine("#[serde(skip_serializing_if = \"Option::is_none\")]"); } } - private get visibility(): string { + private get visibility (): string { if (this._options.visibility === Visibility.Crate) { return "pub(crate) "; } else if (this._options.visibility === Visibility.Public) { return "pub "; } + return ""; } - protected emitStructDefinition(c: ClassType, className: Name): void { + protected emitStructDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine( "#[derive(", this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", this._options.derivePartialEq ? "PartialEq, " : "", - "Serialize, Deserialize)]" + "Serialize, Deserialize)]", ); // List the possible naming styles for every class property - const propertiesNamingStyles: { [key: string]: string[] } = {}; + const propertiesNamingStyles: { [key: string]: string[], } = {}; this.forEachClassProperty(c, "none", (_name, jsonName, _prop) => { propertiesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName); }); @@ -419,13 +425,13 @@ export class RustRenderer extends ConvenienceRenderer { this.emitBlock(["pub struct ", className], structBody); } - protected emitBlock(line: Sourcelike, f: () => void): void { + protected emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected emitUnion(u: UnionType, unionName: Name): void { + protected emitUnion (u: UnionType, unionName: Name): void { const isMaybeWithSingleType = nullableFromUnion(u); if (isMaybeWithSingleType !== null) { @@ -438,7 +444,7 @@ export class RustRenderer extends ConvenienceRenderer { this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", this._options.derivePartialEq ? "PartialEq, " : "", - "Serialize, Deserialize)]" + "Serialize, Deserialize)]", ); this.emitLine("#[serde(untagged)]"); @@ -449,22 +455,22 @@ export class RustRenderer extends ConvenienceRenderer { this.forEachUnionMember(u, nonNulls, blankLines, null, (fieldName, t) => { const rustType = this.breakCycle(t, true); this.emitLine([fieldName, "(", rustType, "),"]); - }) + }), ); } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine( "#[derive(", this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", this._options.derivePartialEq ? "PartialEq, " : "", - "Serialize, Deserialize)]" + "Serialize, Deserialize)]", ); // List the possible naming styles for every enum case - const enumCasesNamingStyles: { [key: string]: string[] } = {}; + const enumCasesNamingStyles: { [key: string]: string[], } = {}; this.forEachEnumCase(e, "none", (_name, jsonName) => { enumCasesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName); }); @@ -481,15 +487,15 @@ export class RustRenderer extends ConvenienceRenderer { this.forEachEnumCase(e, blankLines, (name, jsonName) => { this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle); this.emitLine([name, ","]); - }) + }), ); } - protected emitTopLevelAlias(t: Type, name: Name): void { + protected emitTopLevelAlias (t: Type, name: Name): void { this.emitLine("pub type ", name, " = ", this.rustType(t), ";"); } - protected emitLeadingComments(): void { + protected emitLeadingComments (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); return; @@ -508,14 +514,15 @@ export class RustRenderer extends ConvenienceRenderer { // fn main() { // let json = r#"{"answer": 42}"#; // let model: ${topLevelName} = serde_json::from_str(&json).unwrap(); -// }` +// }`, ); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { if (this._options.leadingComments) { this.emitLeadingComments(); } + this.ensureBlankLine(); if (this._options.edition2018) { this.emitLine("use serde::{Serialize, Deserialize};"); @@ -530,19 +537,19 @@ export class RustRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading", (t, name) => this.emitTopLevelAlias(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, name: Name) => this.emitStructDefinition(c, name), (e, name) => this.emitEnumDefinition(e, name), - (u, name) => this.emitUnion(u, name) + (u, name) => this.emitUnion(u, name), ); } } -function getPreferedNamingStyle(namingStyleOccurences: string[], defaultStyle: string): string { +function getPreferedNamingStyle (namingStyleOccurences: string[], defaultStyle: string): string { const occurrences = Object.fromEntries(Object.keys(namingStyles).map(key => [key, 0])); namingStyleOccurences.forEach(style => ++occurrences[style]); const max = Math.max(...Object.values(occurrences)); @@ -552,22 +559,25 @@ function getPreferedNamingStyle(namingStyleOccurences: string[], defaultStyle: s if (preferedStyles.includes(defaultStyle)) { return defaultStyle; } + return preferedStyles[0]; } -function listMatchingNamingStyles(name: string): string[] { +function listMatchingNamingStyles (name: string): string[] { return Object.entries(namingStyles) .filter(([_, { regex }]) => regex.test(name)) .map(([namingStyle, _]) => namingStyle); } -function nameToNamingStyle(name: string, style: string): string { +function nameToNamingStyle (name: string, style: string): string { if (namingStyles[style].regex.test(name)) { return name; } + const fromStyle = listMatchingNamingStyles(name)[0]; if (fromStyle === undefined) { return name; } + return namingStyles[style].fromParts(namingStyles[fromStyle].toParts(name)); } diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts index 56437c02b..3d93c0343 100644 --- a/packages/quicktype-core/src/language/Scala3.ts +++ b/packages/quicktype-core/src/language/Scala3.ts @@ -1,8 +1,12 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { EnumOption, Option, StringOption, OptionValues, getOptionValues } from "../RendererOptions"; -import { Sourcelike, maybeAnnotated } from "../Source"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated } from "../Source"; import { allLowerWordStyle, allUpperWordStyle, @@ -12,13 +16,14 @@ import { isLetterOrUnderscore, isNumeric, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../support/Strings"; import { assertNever } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, ClassProperty, ClassType, EnumType, MapType, ObjectType, Type, UnionType } from "../Type"; +import { type ClassProperty, type ClassType, type EnumType, type ObjectType, type Type, type UnionType } from "../Type"; +import { ArrayType, MapType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; export enum Framework { None, @@ -33,11 +38,11 @@ export const scala3Options = { [ ["just-types", Framework.None], ["circe", Framework.Circe], - ["upickle", Framework.Upickle] + ["upickle", Framework.Upickle], ], - undefined + undefined, ), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), }; // Use backticks for param names with symbols @@ -60,13 +65,13 @@ const invalidSymbols = [ "/", ";", "'", - '"', + "\"", "{", "}", ":", "~", "`", - "." + ".", ]; const keywords = [ @@ -125,7 +130,7 @@ const keywords = [ "Array", "List", "Map", - "Enum" + "Enum", ]; /** @@ -149,17 +154,17 @@ const wrapOption = (s: string, optional: boolean): string => { } }; -function isPartCharacter(codePoint: number): boolean { +function isPartCharacter (codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter(codePoint: number): boolean { +function isStartCharacter (codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function scalaNameStyle(isUpper: boolean, original: string): string { +function scalaNameStyle (isUpper: boolean, original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -169,7 +174,7 @@ function scalaNameStyle(isUpper: boolean, original: string): string { isUpper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -177,7 +182,7 @@ function scalaNameStyle(isUpper: boolean, original: string): string { return "\\u" + intToHex(codePoint, 4); } */ -//const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); +// const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); /* function stringEscape(s: string): string { // "$this" is a template string in Kotlin so we have to escape $ @@ -188,94 +193,94 @@ const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s) const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); export class Scala3Renderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _scalaOptions: OptionValues + protected readonly _scalaOptions: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords; } - protected forbiddenForObjectProperties(_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected topLevelNameStyle(rawName: string): string { + protected topLevelNameStyle (rawName: string): string { return scalaNameStyle(true, rawName); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return upperNamingFunction; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return lowerNamingFunction; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock( + protected emitBlock ( line: Sourcelike, f: () => void, - delimiter: "curly" | "paren" | "lambda" | "none" = "curly" + delimiter: "curly" | "paren" | "lambda" | "none" = "curly", ): void { const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" - ? ["(", ")"] - : delimiter === "none" - ? ["", ""] - : ["{", "})"]; + ? ["(", ")"] + : delimiter === "none" + ? ["", ""] + : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); } - protected anySourceType(optional: boolean): Sourcelike { + protected anySourceType (optional: boolean): Sourcelike { return [wrapOption("Any", optional)]; } // (asarazan): I've broken out the following two functions // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType(arrayType: ArrayType, withIssues = false): Sourcelike { + protected arrayType (arrayType: ArrayType, withIssues = false): Sourcelike { return ["Seq[", this.scalaType(arrayType.items, withIssues), "]"]; } - protected mapType(mapType: MapType, withIssues = false): Sourcelike { + protected mapType (mapType: MapType, withIssues = false): Sourcelike { return ["Map[String, ", this.scalaType(mapType.values, withIssues), "]"]; } - protected scalaType(t: Type, withIssues = false, noOptional = false): Sourcelike { + protected scalaType (t: Type, withIssues = false, noOptional = false): Sourcelike { return matchType( t, _anyType => { return maybeAnnotated(withIssues, anyTypeIssueAnnotation, this.anySourceType(!noOptional)); }, _nullType => { - //return "None.type" + // return "None.type" return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(!noOptional)); }, _boolType => "Boolean", @@ -295,15 +300,17 @@ export class Scala3Renderer extends ConvenienceRenderer { return ["Option[", this.scalaType(nullable, withIssues), "]"]; } } + return this.nameForNamedType(unionType); - } + }, ); } - protected emitUsageHeader(): void { + + protected emitUsageHeader (): void { // To be overridden } - protected emitHeader(): void { + protected emitHeader (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -315,22 +322,22 @@ export class Scala3Renderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { const elementType = this.scalaType(t.items); this.emitLine(["type ", name, " = List[", elementType, "]"]); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { const elementType = this.scalaType(t.values); this.emitLine(["type ", name, " = Map[String, ", elementType, "]"]); } - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + protected emitEmptyClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("case class ", className, "()"); } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition (c: ClassType, className: Name): void { if (c.getProperties().size === 0) { this.emitEmptyClassDefinition(c, className); return; @@ -367,6 +374,7 @@ export class Scala3Renderer extends ConvenienceRenderer { for (const emit of meta) { emit(); } + const nameNeedsBackticks = jsonName.endsWith("_") || shouldAddBacktick(jsonName); const nameWithBackticks = nameNeedsBackticks ? "`" + jsonName + "`" : jsonName; this.emitLine( @@ -375,7 +383,7 @@ export class Scala3Renderer extends ConvenienceRenderer { " : ", scalaType(p), p.isOptional ? " = None" : nullableOrOptional ? " = None" : "", - last ? "" : "," + last ? "" : ",", ); if (meta.length > 0 && !last) { @@ -389,11 +397,11 @@ export class Scala3Renderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(); } - protected emitClassDefinitionMethods() { + protected emitClassDefinitionMethods () { this.emitLine(")"); } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock( @@ -403,6 +411,7 @@ export class Scala3Renderer extends ConvenienceRenderer { if (count > 0) { this.emitItem("\t case "); } + this.forEachEnumCase(e, "none", (name, jsonName) => { if (!(jsonName == "")) { const backticks = @@ -412,22 +421,24 @@ export class Scala3Renderer extends ConvenienceRenderer { if (backticks) { this.emitItem("`"); } + this.emitItemOnce([name]); if (backticks) { this.emitItem("`"); } + if (--count > 0) this.emitItem([","]); } else { --count; } }); }, - "none" + "none", ); } - protected emitUnionDefinition(u: UnionType, unionName: Name): void { - function sortBy(t: Type): string { + protected emitUnionDefinition (u: UnionType, unionName: Name): void { + function sortBy (t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -436,7 +447,7 @@ export class Scala3Renderer extends ConvenienceRenderer { this.emitDescription(this.descriptionForType(u)); const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); - const theTypes: Array = []; + const theTypes: Sourcelike[] = []; this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { theTypes.push(this.scalaType(t)); }); @@ -451,7 +462,7 @@ export class Scala3Renderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.emitHeader(); // Top-level arrays, maps @@ -467,17 +478,17 @@ export class Scala3Renderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n) + (u, n) => this.emitUnionDefinition(u, n), ); } } export class UpickleRenderer extends Scala3Renderer { - protected emitClassDefinitionMethods() { + protected emitClassDefinitionMethods () { this.emitLine(") derives ReadWriter "); } - protected emitHeader(): void { + protected emitHeader (): void { super.emitHeader(); this.emitLine("import upickle.default.*"); @@ -486,7 +497,7 @@ export class UpickleRenderer extends Scala3Renderer { } export class Smithy4sRenderer extends Scala3Renderer { - protected emitHeader(): void { + protected emitHeader (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -498,22 +509,22 @@ export class Smithy4sRenderer extends Scala3Renderer { this.ensureBlankLine(); } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { const elementType = this.scalaType(t.items); this.emitLine(["list ", name, " { member : ", elementType, "}"]); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { const elementType = this.scalaType(t.values); this.emitLine(["map ", name, " { map[ key : String , value : ", elementType, "}"]); } - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + protected emitEmptyClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("structure ", className, "{}"); } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.ensureBlankLine(); @@ -527,12 +538,12 @@ export class Smithy4sRenderer extends Scala3Renderer { !isNaN(parseInt(jsonName.charAt(0))) if (backticks) {this.emitItem("`")} else */ this.emitLine(); - this.emitItem([name, ' = "', jsonName, '"']); + this.emitItem([name, " = \"", jsonName, "\""]); // if (backticks) {this.emitItem("`")} if (--count > 0) this.emitItem([","]); - //} else { - //--count - //} + // } else { + // --count + // } }); this.ensureBlankLine(); this.emitItem(["}"]); @@ -540,9 +551,9 @@ export class Smithy4sRenderer extends Scala3Renderer { } export class CirceRenderer extends Scala3Renderer { - seenUnionTypes: Array = []; + seenUnionTypes: string[] = []; - protected circeEncoderForType(t: Type, _ = false, noOptional = false, paramName: string = ""): Sourcelike { + protected circeEncoderForType (t: Type, _ = false, noOptional = false, paramName: string = ""): Sourcelike { return matchType( t, _anyType => ["Encoder.encodeJson(", paramName, ")"], @@ -564,26 +575,27 @@ export class CirceRenderer extends Scala3Renderer { return ["Encoder.AsObject[Option[", this.nameForNamedType(nullable), "]]"]; } } + return ["Encoder.AsObject[", this.nameForNamedType(unionType), "]"]; - } + }, ); } - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + protected emitEmptyClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.ensureBlankLine(); this.emitLine("case class ", className, "() derives Encoder.AsObject, Decoder"); } - protected anySourceType(optional: boolean): Sourcelike { + protected anySourceType (optional: boolean): Sourcelike { return [wrapOption("Json", optional)]; } - protected emitClassDefinitionMethods() { + protected emitClassDefinitionMethods () { this.emitLine(") derives Encoder.AsObject, Decoder"); } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.ensureBlankLine(); @@ -596,17 +608,17 @@ export class CirceRenderer extends Scala3Renderer { jsonName.includes(" ") || !isNaN(parseInt(jsonName.charAt(0))) if (backticks) {this.emitItem("`")} else */ - this.emitItem(['"', jsonName, '"']); + this.emitItem(["\"", jsonName, "\""]); // if (backticks) {this.emitItem("`")} if (--count > 0) this.emitItem([" | "]); - //} else { - //--count - //} + // } else { + // --count + // } }); this.ensureBlankLine(); } - protected emitHeader(): void { + protected emitHeader (): void { super.emitHeader(); this.emitLine("import scala.util.Try"); @@ -617,17 +629,17 @@ export class CirceRenderer extends Scala3Renderer { this.emitLine("// For serialising string unions"); this.emitLine( - "given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) " + "given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) ", ); this.emitLine( - "given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) " + "given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) ", ); this.ensureBlankLine(); this.emitLine("// If a union has a null in, then we'll need this too... "); this.emitLine("type NullValue = None.type"); } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { super.emitTopLevelArray(t, name); const elementType = this.scalaType(t.items); this.emitLine([ @@ -637,11 +649,11 @@ export class CirceRenderer extends Scala3Renderer { elementType, "]] = Encoder.encodeMap[String, ", elementType, - "]" + "]", ]); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { super.emitTopLevelMap(t, name); const elementType = this.scalaType(t.values); this.ensureBlankLine(); @@ -652,12 +664,12 @@ export class CirceRenderer extends Scala3Renderer { elementType, "]] = Encoder.encodeMap[String, ", elementType, - "]" + "]", ]); } - protected emitUnionDefinition(u: UnionType, unionName: Name): void { - function sortBy(t: Type): string { + protected emitUnionDefinition (u: UnionType, unionName: Name): void { + function sortBy (t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -666,7 +678,7 @@ export class CirceRenderer extends Scala3Renderer { this.emitDescription(this.descriptionForType(u)); const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); - const theTypes: Array = []; + const theTypes: Sourcelike[] = []; this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { theTypes.push(this.scalaType(t)); }); @@ -715,7 +727,7 @@ export class CirceRenderer extends Scala3Renderer { " : ", t[0], " => ", - this.circeEncoderForType(t[1], false, false, paramTemp) + this.circeEncoderForType(t[1], false, false, paramTemp), ]); }); }); @@ -725,25 +737,25 @@ export class CirceRenderer extends Scala3Renderer { } export class Scala3TargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Scala3", ["scala3"], "scala"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [scala3Options.framework, scala3Options.packageName]; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): ConvenienceRenderer { const options = getOptionValues(scala3Options, untypedOptionValues); diff --git a/packages/quicktype-core/src/language/Smithy4s.ts b/packages/quicktype-core/src/language/Smithy4s.ts index 3a875be64..8e794fbd5 100644 --- a/packages/quicktype-core/src/language/Smithy4s.ts +++ b/packages/quicktype-core/src/language/Smithy4s.ts @@ -1,8 +1,12 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { EnumOption, Option, StringOption, OptionValues, getOptionValues } from "../RendererOptions"; -import { Sourcelike, maybeAnnotated } from "../Source"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated } from "../Source"; import { allLowerWordStyle, allUpperWordStyle, @@ -12,13 +16,14 @@ import { isLetterOrUnderscore, isNumeric, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../support/Strings"; import { assertNever } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, ClassProperty, ClassType, EnumType, MapType, ObjectType, Type, UnionType } from "../Type"; +import { type ClassProperty, type ClassType, type EnumType, type ObjectType, type Type, type UnionType } from "../Type"; +import { ArrayType, MapType } from "../Type"; import { matchCompoundType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { RenderContext } from "../Renderer"; +import { type RenderContext } from "../Renderer"; export enum Framework { None @@ -26,7 +31,7 @@ export enum Framework { export const SmithyOptions = { framework: new EnumOption("framework", "Serialization framework", [["just-types", Framework.None]], undefined), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), }; // Use backticks for param names with symbols @@ -48,13 +53,13 @@ const invalidSymbols = [ "/", ";", "'", - '"', + "\"", "{", "}", ":", "~", "`", - "." + ".", ]; const keywords = [ @@ -104,7 +109,7 @@ const keywords = [ "Array", "List", "Map", - "Enum" + "Enum", ]; /** @@ -120,17 +125,17 @@ const shouldAddBacktick = (paramName: string): boolean => { ); }; -function isPartCharacter(codePoint: number): boolean { +function isPartCharacter (codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter(codePoint: number): boolean { +function isStartCharacter (codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function scalaNameStyle(isUpper: boolean, original: string): string { +function scalaNameStyle (isUpper: boolean, original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -140,7 +145,7 @@ function scalaNameStyle(isUpper: boolean, original: string): string { isUpper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -148,100 +153,100 @@ const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s) const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); export class Smithy4sRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _scalaOptions: OptionValues + protected readonly _scalaOptions: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords; } - protected forbiddenForObjectProperties(_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected topLevelNameStyle(rawName: string): string { + protected topLevelNameStyle (rawName: string): string { return scalaNameStyle(true, rawName); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return upperNamingFunction; } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return lowerNamingFunction; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock( + protected emitBlock ( line: Sourcelike, f: () => void, - delimiter: "curly" | "paren" | "lambda" | "none" = "curly" + delimiter: "curly" | "paren" | "lambda" | "none" = "curly", ): void { const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" - ? ["(", ")"] - : delimiter === "none" - ? ["", ""] - : ["{", "})"]; + ? ["(", ")"] + : delimiter === "none" + ? ["", ""] + : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); } - protected anySourceType(_: boolean): Sourcelike { + protected anySourceType (_: boolean): Sourcelike { return ["Document"]; } // (asarazan): I've broken out the following two functions // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType(arrayType: ArrayType, _ = false): Sourcelike { - //this.emitTopLevelArray(arrayType, new Name(arrayType.getCombinedName().toString() + "List")) + protected arrayType (arrayType: ArrayType, _ = false): Sourcelike { + // this.emitTopLevelArray(arrayType, new Name(arrayType.getCombinedName().toString() + "List")) return arrayType.getCombinedName().toString() + "List"; } - protected emitArrayType(_: ArrayType, smithyType: Sourcelike): void { + protected emitArrayType (_: ArrayType, smithyType: Sourcelike): void { this.emitLine(["list ", smithyType, " { member : ", "}"]); } - protected mapType(mapType: MapType, _ = false): Sourcelike { + protected mapType (mapType: MapType, _ = false): Sourcelike { return mapType.getCombinedName().toString() + "Map"; - //return [this.scalaType(mapType.values, withIssues), "Map"]; + // return [this.scalaType(mapType.values, withIssues), "Map"]; } - protected scalaType(t: Type, withIssues = false, noOptional = false): Sourcelike { + protected scalaType (t: Type, withIssues = false, noOptional = false): Sourcelike { return matchType( t, _anyType => { return maybeAnnotated(withIssues, anyTypeIssueAnnotation, this.anySourceType(!noOptional)); }, _nullType => { - //return "None.type" + // return "None.type" return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(!noOptional)); }, _boolType => "Boolean", @@ -257,16 +262,17 @@ export class Smithy4sRenderer extends ConvenienceRenderer { if (nullable !== null) { return [this.scalaType(nullable, withIssues)]; } + return this.nameForNamedType(unionType); - } + }, ); } - protected emitUsageHeader(): void { + protected emitUsageHeader (): void { // To be overridden } - protected emitHeader(): void { + protected emitHeader (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -274,7 +280,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { } this.ensureBlankLine(); - this.emitLine('$version: "2"'); + this.emitLine("$version: \"2\""); this.emitLine("namespace ", this._scalaOptions.packageName); this.ensureBlankLine(); @@ -282,22 +288,22 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitTopLevelArray(t: ArrayType, name: Name): void { + protected emitTopLevelArray (t: ArrayType, name: Name): void { const elementType = this.scalaType(t.items); this.emitLine(["list ", name, " { member : ", elementType, "}"]); } - protected emitTopLevelMap(t: MapType, name: Name): void { + protected emitTopLevelMap (t: MapType, name: Name): void { const elementType = this.scalaType(t.values); this.emitLine(["map ", name, " { map[ key : String , value : ", elementType, "}"]); } - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + protected emitEmptyClassDefinition (c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("structure ", className, "{}"); } - protected emitClassDefinition(c: ClassType, className: Name): void { + protected emitClassDefinition (c: ClassType, className: Name): void { if (c.getProperties().size === 0) { this.emitEmptyClassDefinition(c, className); return; @@ -311,7 +317,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { } }; - const emitLater: Array = []; + const emitLater: ClassProperty[] = []; this.emitDescription(this.descriptionForType(c)); this.emitLine("structure ", className, " {"); @@ -342,6 +348,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { for (const emit of meta) { emit(); } + const nameNeedsBackticks = jsonName.endsWith("_") || shouldAddBacktick(jsonName); const nameWithBackticks = nameNeedsBackticks ? "`" + jsonName + "`" : jsonName; this.emitLine( @@ -350,7 +357,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { " : ", scalaType(p), - last ? "" : "," + last ? "" : ",", ); if (meta.length > 0 && !last) { @@ -363,12 +370,13 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(emitLater); } - protected emitClassDefinitionMethods(arrayTypes: ClassProperty[]) { + protected emitClassDefinitionMethods (arrayTypes: ClassProperty[]) { this.emitLine("}"); arrayTypes.forEach(p => { - function ignore(_: T): void { + function ignore (_: T): void { return; } + matchCompoundType( p.type, at => { @@ -377,7 +385,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(at, true), "{ member: ", this.scalaType(at.items, true), - "}" + "}", ]); }, ignore, @@ -387,16 +395,16 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(mt, true), "{ key: String , value: ", this.scalaType(mt.values, true), - "}" + "}", ]); }, ignore, - ignore + ignore, ); }); } - protected emitEnumDefinition(e: EnumType, enumName: Name): void { + protected emitEnumDefinition (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.ensureBlankLine(); @@ -412,37 +420,38 @@ export class Smithy4sRenderer extends ConvenienceRenderer { if (backticks) {this.emitItem("`")} else */ this.emitLine(); - this.emitItem([name, ' = "', jsonName, '"']); + this.emitItem([name, " = \"", jsonName, "\""]); // if (backticks) {this.emitItem("`")} if (--count > 0) this.emitItem([","]); - //} else { - //--count - //} + // } else { + // --count + // } }); this.ensureBlankLine(); this.emitItem(["}"]); } - protected emitUnionDefinition(u: UnionType, unionName: Name): void { - function sortBy(t: Type): string { + protected emitUnionDefinition (u: UnionType, unionName: Name): void { + function sortBy (t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; } - const emitLater: Array = []; + const emitLater: Type[] = []; this.emitDescription(this.descriptionForType(u)); const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); - const theTypes: Array = []; + const theTypes: Sourcelike[] = []; this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { const laterType = t.kind === "array" || t.kind === "map"; if (laterType) { emitLater.push(t); } + theTypes.push(this.scalaType(t)); }); if (maybeNull !== null) { @@ -459,9 +468,10 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.ensureBlankLine(); emitLater.forEach(p => { - function ignore(_: T): void { + function ignore (_: T): void { return; } + matchCompoundType( p, at => { @@ -470,7 +480,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(at, true), "{ member: ", this.scalaType(at.items, true), - "}" + "}", ]); }, ignore, @@ -480,16 +490,16 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(mt, true), "{ key: String , value: ", this.scalaType(mt.values, true), - "}" + "}", ]); }, ignore, - ignore + ignore, ); }); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { this.emitHeader(); // Top-level arrays, maps @@ -505,31 +515,31 @@ export class Smithy4sRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n) + (u, n) => this.emitUnionDefinition(u, n), ); } } export class SmithyTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Smithy", ["Smithy"], "smithy"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [SmithyOptions.framework, SmithyOptions.packageName]; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): ConvenienceRenderer { const options = getOptionValues(SmithyOptions, untypedOptionValues); diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift.ts index 04fc431a1..bc8cd35ca 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift.ts @@ -3,23 +3,29 @@ import { assert, defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { - Type, - ClassType, + type Type, + type ClassType, + type UnionType, + type TypeKind, + type ClassProperty, + type TransformedStringTypeKind, + type PrimitiveStringTypeKind, +} from "../Type"; +import { EnumType, - UnionType, ArrayType, MapType, - TypeKind, - ClassProperty, - TransformedStringTypeKind, - PrimitiveStringTypeKind } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { BooleanOption, EnumOption, Option, StringOption, OptionValues, getOptionValues } from "../RendererOptions"; -import { Sourcelike, maybeAnnotated, modifySource } from "../Source"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike} from "../Source"; +import { maybeAnnotated, modifySource } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { legalizeCharacters, isLetterOrUnderscore, @@ -35,12 +41,13 @@ import { allLowerWordStyle, allUpperWordStyle, camelCase, - addPrefixIfNecessary + addPrefixIfNecessary, } from "../support/Strings"; -import { RenderContext, ForEachPosition } from "../Renderer"; -import { StringTypeMapping } from "../TypeBuilder"; +import { type RenderContext, type ForEachPosition } from "../Renderer"; +import { type StringTypeMapping } from "../TypeBuilder"; import { panic } from "../support/Support"; -import { DefaultDateTimeRecognizer, DateTimeRecognizer } from "../DateTime"; +import { type DateTimeRecognizer } from "../DateTime"; +import { DefaultDateTimeRecognizer } from "../DateTime"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; const MAX_SAMELINE_PROPERTIES = 4; @@ -53,7 +60,7 @@ export const swiftOptions = { namedTypePrefix: new StringOption("type-prefix", "Prefix for type names", "PREFIX", "", "secondary"), useClasses: new EnumOption("struct-or-class", "Structs or classes", [ ["struct", false], - ["class", true] + ["class", true], ]), mutableProperties: new BooleanOption("mutable-properties", "Use var instead of let for object properties", false), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), @@ -62,16 +69,16 @@ export const swiftOptions = { "Code density", [ ["dense", true], - ["normal", false] + ["normal", false], ], "dense", - "secondary" + "secondary", ), linux: new BooleanOption("support-linux", "Support Linux", false, "secondary"), objcSupport: new BooleanOption( "objective-c-support", "Objects inherit from NSObject and @objcMembers is added to classes", - false + false, ), optionalEnums: new BooleanOption("optional-enums", "If no matching case is found enum value is set to null", false), swift5Support: new BooleanOption("swift-5-support", "Renders output in a Swift 5 compatible mode", false), @@ -79,17 +86,17 @@ export const swiftOptions = { multiFileOutput: new BooleanOption( "multi-file-output", "Renders each top-level object in its own Swift file", - false + false, ), accessLevel: new EnumOption( "access-level", "Access level", [ ["internal", "internal"], - ["public", "public"] + ["public", "public"], ], "internal", - "secondary" + "secondary", ), protocol: new EnumOption( "protocol", @@ -97,11 +104,11 @@ export const swiftOptions = { [ ["none", { equatable: false, hashable: false }], ["equatable", { equatable: true, hashable: false }], - ["hashable", { equatable: false, hashable: true }] + ["hashable", { equatable: false, hashable: true }], ], "none", - "secondary" - ) + "secondary", + ), }; // These are all recognized by Swift as ISO8601 date-times: @@ -118,24 +125,24 @@ export const swiftOptions = { const swiftDateTimeRegex = /^\d+-\d+-\d+T\d+:\d+:\d+([zZ]|[+-]\d+(:\d+)?)$/; class SwiftDateTimeRecognizer extends DefaultDateTimeRecognizer { - isDateTime(str: string): boolean { - return str.match(swiftDateTimeRegex) !== null; + isDateTime (str: string): boolean { + return swiftDateTimeRegex.exec(str) !== null; } } export interface SwiftProperty { - name: Name; jsonName: string; + name: Name; parameter: ClassProperty; position: ForEachPosition; } export class SwiftTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Swift", ["swift", "swift4"], "swift"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ swiftOptions.justTypes, swiftOptions.useClasses, @@ -153,29 +160,29 @@ export class SwiftTargetLanguage extends TargetLanguage { swiftOptions.sendable, swiftOptions.swift5Support, swiftOptions.multiFileOutput, - swiftOptions.mutableProperties + swiftOptions.mutableProperties, ]; } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date-time", "date-time"); return mapping; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + get supportsUnionsWithBothNumberTypes (): boolean { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): SwiftRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): SwiftRenderer { return new SwiftRenderer(this, renderContext, getOptionValues(swiftOptions, untypedOptionValues)); } - get dateTimeRecognizer(): DateTimeRecognizer { + get dateTimeRecognizer (): DateTimeRecognizer { return new SwiftDateTimeRecognizer(); } } @@ -279,24 +286,24 @@ const keywords = [ "convertDict", "convertDouble", "jsonString", - "jsonData" + "jsonData", ]; -function isPartCharacter(codePoint: number): boolean { +function isPartCharacter (codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter(codePoint: number): boolean { +function isStartCharacter (codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function swiftNameStyle( +function swiftNameStyle ( prefix: string, isUpper: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle + acronymsStyle: (s: string) => string = allUpperWordStyle, ): string { const words = splitIntoWords(original); const combined = combineWords( @@ -307,12 +314,12 @@ function swiftNameStyle( isUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, "", - isStartCharacter + isStartCharacter, ); return addPrefixIfNecessary(prefix, combined); } -function unicodeEscape(codePoint: number): string { +function unicodeEscape (codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; } @@ -320,91 +327,94 @@ const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicod export class SwiftRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; + private _needAny = false; + private _needNull = false; - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { if (this._options.alamofire) { return ["DataRequest", ...keywords]; } + return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { return { names: ["fromURL", "json"], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("upper", s => - swiftNameStyle(this._options.namedTypePrefix, true, s, acronymStyle(this._options.acronymStyle)) + swiftNameStyle(this._options.namedTypePrefix, true, s, acronymStyle(this._options.acronymStyle)), ); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return this.lowerNamingFunction; } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return this.lowerNamingFunction; } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return this.lowerNamingFunction; } - protected isImplicitCycleBreaker(t: Type): boolean { + protected isImplicitCycleBreaker (t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } - protected emitDescriptionBlock(lines: Sourcelike[]): void { + protected emitDescriptionBlock (lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: "/// " }); } - private emitBlock(line: Sourcelike, f: () => void): void { + private emitBlock (line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - private emitBlockWithAccess(line: Sourcelike, f: () => void): void { + private emitBlockWithAccess (line: Sourcelike, f: () => void): void { this.emitBlock([this.accessLevel, line], f); } - private justTypesCase(justTypes: Sourcelike, notJustTypes: Sourcelike): Sourcelike { + private justTypesCase (justTypes: Sourcelike, notJustTypes: Sourcelike): Sourcelike { if (this._options.justTypes) return justTypes; else return notJustTypes; } - private get lowerNamingFunction() { + private get lowerNamingFunction () { return funPrefixNamer("lower", s => swiftNameStyle("", false, s, acronymStyle(this._options.acronymStyle))); } - protected swiftPropertyType(p: ClassProperty): Sourcelike { - if (p.isOptional || (this._options.optionalEnums && p.type.kind === "enum")) { + protected swiftPropertyType (p: ClassProperty): Sourcelike { + if (p.isOptional || this._options.optionalEnums && p.type.kind === "enum") { return [this.swiftType(p.type, true, true), "?"]; } else { return this.swiftType(p.type, true); } } - protected swiftType(t: Type, withIssues = false, noOptional = false): Sourcelike { + protected swiftType (t: Type, withIssues = false, noOptional = false): Sourcelike { const optional = noOptional ? "" : "?"; return matchType( t, @@ -413,7 +423,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return maybeAnnotated( withIssues, anyTypeIssueAnnotation, - this.justTypesCase(["Any", optional], "JSONAny") + this.justTypesCase(["Any", optional], "JSONAny"), ); }, _nullType => { @@ -421,7 +431,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return maybeAnnotated( withIssues, nullTypeIssueAnnotation, - this.justTypesCase("NSNull", ["JSONNull", optional]) + this.justTypesCase("NSNull", ["JSONNull", optional]), ); }, _boolType => "Bool", @@ -443,21 +453,23 @@ export class SwiftRenderer extends ConvenienceRenderer { } else { return panic(`Transformed string type ${transformedStringType.kind} not supported`); } - } + }, ); } - protected proposedUnionMemberNameForTypeKind(kind: TypeKind): string | null { + protected proposedUnionMemberNameForTypeKind (kind: TypeKind): string | null { if (kind === "enum") { return "enumeration"; } + if (kind === "union") { return "one_of"; } + return null; } - private renderSingleFileHeaderComments(): void { + private renderSingleFileHeaderComments (): void { this.emitLineOnce("// This file was generated from JSON Schema using quicktype, do not modify it directly."); this.emitLineOnce("// To parse the JSON, add this file to your project and do:"); this.emitLineOnce("//"); @@ -468,7 +480,7 @@ export class SwiftRenderer extends ConvenienceRenderer { modifySource(camelCase, topLevelName), " = try ", topLevelName, - "(json)" + "(json)", ); } else { this.emitLineOnce( @@ -477,19 +489,19 @@ export class SwiftRenderer extends ConvenienceRenderer { " = ", "try? JSONDecoder().decode(", topLevelName, - ".self, from: jsonData)" + ".self, from: jsonData)", ); } }); } - private renderHeader(type: Type, name: Name): void { + private renderHeader (type: Type, name: Name): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else if (!this._options.justTypes) { if (this._options.multiFileOutput) { this.emitLineOnce( - "// This file was generated from JSON Schema using quicktype, do not modify it directly." + "// This file was generated from JSON Schema using quicktype, do not modify it directly.", ); this.emitLineOnce("// To parse the JSON, add this file to your project and do:"); this.emitLineOnce("//"); @@ -502,7 +514,7 @@ export class SwiftRenderer extends ConvenienceRenderer { " = ", "try? newJSONDecoder().decode(", name, - ".self, from: jsonData)" + ".self, from: jsonData)", ); } } @@ -522,30 +534,33 @@ export class SwiftRenderer extends ConvenienceRenderer { this.emitLine("//"); this.emitLine("// Hashable or Equatable:"); this.emitLine( - "// The compiler will not be able to synthesize the implementation of Hashable or Equatable" + "// The compiler will not be able to synthesize the implementation of Hashable or Equatable", ); this.emitLine( - "// for types that require the use of JSONAny, nor will the implementation of Hashable be" + "// for types that require the use of JSONAny, nor will the implementation of Hashable be", ); this.emitLine("// synthesized for types that have collections (such as arrays or dictionaries)."); } } + this.ensureBlankLine(); this.emitLineOnce("import Foundation"); if (!this._options.justTypes && this._options.alamofire) { this.emitLineOnce("import Alamofire"); } + if (this._options.optionalEnums) { this.emitLineOnce("import OptionallyDecodable // https://github.com/idrougge/OptionallyDecodable"); } + this.ensureBlankLine(); } - private renderTopLevelAlias(t: Type, name: Name): void { + private renderTopLevelAlias (t: Type, name: Name): void { this.emitLine(this.accessLevel, "typealias ", name, " = ", this.swiftType(t, true)); } - protected getProtocolsArray(kind: "struct" | "class" | "enum"): string[] { + protected getProtocolsArray (kind: "struct" | "class" | "enum"): string[] { const protocols: string[] = []; // [Michael Fey (@MrRooni), 2019-4-24] Technically NSObject isn't a "protocol" in this instance, but this felt like the best place to slot in this superclass declaration. @@ -574,19 +589,20 @@ export class SwiftRenderer extends ConvenienceRenderer { return protocols; } - private getProtocolString( + private getProtocolString ( kind: "struct" | "class" | "enum", - baseClass: string | undefined = undefined + baseClass: string | undefined = undefined, ): Sourcelike { let protocols = this.getProtocolsArray(kind); if (baseClass) { protocols.unshift(baseClass); } + return protocols.length > 0 ? ": " + protocols.join(", ") : ""; } - private getEnumPropertyGroups(c: ClassType) { - type PropertyGroup = { name: Name; label?: string }[]; + private getEnumPropertyGroups (c: ClassType) { + type PropertyGroup = Array<{ label?: string, name: Name, }>; let groups: PropertyGroup[] = []; let group: PropertyGroup = []; @@ -602,6 +618,7 @@ export class SwiftRenderer extends ConvenienceRenderer { groups.push(group); group = []; } + groups.push([{ name, label }]); } }); @@ -614,13 +631,13 @@ export class SwiftRenderer extends ConvenienceRenderer { } /// Access level with trailing space (e.g. "public "), or empty string - private get accessLevel(): string { + private get accessLevel (): string { return this._options.accessLevel === "internal" ? "" // internal is default, so we don't have to emit it : this._options.accessLevel + " "; } - private get objcMembersDeclaration(): string { + private get objcMembersDeclaration (): string { if (this._options.objcSupport) { return "@objcMembers "; } @@ -629,7 +646,7 @@ export class SwiftRenderer extends ConvenienceRenderer { } /// startFile takes a file name, appends ".swift" to it and sets it as the current filename. - protected startFile(basename: Sourcelike): void { + protected startFile (basename: Sourcelike): void { if (this._options.multiFileOutput === false) { return; } @@ -641,7 +658,7 @@ export class SwiftRenderer extends ConvenienceRenderer { } /// endFile pushes the current file name onto the collection of finished files and then resets the current file name. These finished files are used in index.ts to write the output. - protected endFile(): void { + protected endFile (): void { if (this._options.multiFileOutput === false) { return; } @@ -650,18 +667,18 @@ export class SwiftRenderer extends ConvenienceRenderer { this._currentFilename = undefined; } - protected propertyLinesDefinition(name: Name, parameter: ClassProperty): Sourcelike { + protected propertyLinesDefinition (name: Name, parameter: ClassProperty): Sourcelike { const useMutableProperties = this._options.mutableProperties; return [ this.accessLevel, useMutableProperties ? "var " : "let ", name, ": ", - this.swiftPropertyType(parameter) + this.swiftPropertyType(parameter), ]; } - private renderClassDefinition(c: ClassType, className: Name): void { + private renderClassDefinition (c: ClassType, className: Name): void { this.startFile(className); this.renderHeader(c, className); @@ -690,13 +707,13 @@ export class SwiftRenderer extends ConvenienceRenderer { let sources: Sourcelike[] = [ [ this._options.optionalEnums && lastProperty.type.kind === "enum" - ? `@OptionallyDecodable ` + ? "@OptionallyDecodable " : "", this.accessLevel, - useMutableProperties || (this._options.optionalEnums && lastProperty.type.kind === "enum") + useMutableProperties || this._options.optionalEnums && lastProperty.type.kind === "enum" ? "var " - : "let " - ] + : "let ", + ], ]; lastNames.forEach((n, i) => { if (i > 0) sources.push(", "); @@ -719,9 +736,11 @@ export class SwiftRenderer extends ConvenienceRenderer { ) { emitLastProperty(); } + if (lastProperty === undefined) { lastProperty = p; } + lastNames.push(name); if (description !== undefined) { this.emitDescription(description); @@ -749,11 +768,11 @@ export class SwiftRenderer extends ConvenienceRenderer { for (const group of groups) { const { name, label } = group[0]; if (this._options.explicitCodingKeys && label !== undefined) { - this.emitLine("case ", name, ' = "', label, '"'); + this.emitLine("case ", name, " = \"", label, "\""); } else { const names = arrayIntercalate( ", ", - group.map(p => p.name) + group.map(p => p.name), ); this.emitLine("case ", names); } @@ -778,6 +797,7 @@ export class SwiftRenderer extends ConvenienceRenderer { if (propertiesLines.length > 0) propertiesLines.push(", "); propertiesLines.push(property.name, ": ", this.swiftPropertyType(property.parameter)); } + if (this.propertyCount(c) === 0 && this._options.objcSupport) { this.emitBlockWithAccess(["override init()"], () => { return ""; @@ -806,7 +826,7 @@ export class SwiftRenderer extends ConvenienceRenderer { this.endFile(); } - protected initializableProperties(c: ClassType): SwiftProperty[] { + protected initializableProperties (c: ClassType): SwiftProperty[] { const properties: SwiftProperty[] = []; this.forEachClassProperty(c, "none", (name, jsonName, parameter, position) => { const property = { name, jsonName, parameter, position }; @@ -815,7 +835,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return properties; } - private emitNewEncoderDecoder(): void { + private emitNewEncoderDecoder (): void { this.emitBlock("func newJSONDecoder() -> JSONDecoder", () => { this.emitLine("let decoder = JSONDecoder()"); if (!this._options.linux) { @@ -842,6 +862,7 @@ export class SwiftRenderer extends ConvenienceRenderer { throw DecodingError.typeMismatch(Date.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date")) })`); } + this.emitLine("return decoder"); }); this.ensureBlankLine(); @@ -859,11 +880,12 @@ formatter.timeZone = TimeZone(secondsFromGMT: 0) formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX" encoder.dateEncodingStrategy = .formatted(formatter)`); } + this.emitLine("return encoder"); }); } - private emitConvenienceInitializersExtension(c: ClassType, className: Name): void { + private emitConvenienceInitializersExtension (c: ClassType, className: Name): void { const isClass = this._options.useClasses || this.isCycleBreakerType(c); const convenience = isClass ? "convenience " : ""; @@ -875,6 +897,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } else { this.emitLine("let _ = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)"); } + let args: Sourcelike[] = []; this.forEachClassProperty(c, "none", name => { if (args.length > 0) args.push(", "); @@ -887,18 +910,19 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.emitLine("self = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)"); }); } + this.ensureBlankLine(); this.emitBlock( [convenience, "init(_ json: String, using encoding: String.Encoding = .utf8) throws"], () => { this.emitBlock("guard let data = json.data(using: encoding) else", () => { - this.emitLine(`throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)`); + this.emitLine("throw NSError(domain: \"JSONDecoding\", code: 0, userInfo: nil)"); }); this.emitLine("try self.init(data: data)"); - } + }, ); this.ensureBlankLine(); - this.emitBlock([convenience, `init(fromURL url: URL) throws`], () => { + this.emitBlock([convenience, "init(fromURL url: URL) throws"], () => { this.emitLine("try self.init(data: try Data(contentsOf: url))"); }); @@ -907,17 +931,17 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); // Convenience serializers this.ensureBlankLine(); - this.emitBlock(`func jsonData() throws -> Data`, () => { + this.emitBlock("func jsonData() throws -> Data", () => { this.emitLine("return try newJSONEncoder().encode(self)"); }); this.ensureBlankLine(); - this.emitBlock(`func jsonString(encoding: String.Encoding = .utf8) throws -> String?`, () => { + this.emitBlock("func jsonString(encoding: String.Encoding = .utf8) throws -> String?", () => { this.emitLine("return String(data: try self.jsonData(), encoding: encoding)"); }); }); } - private renderEnumDefinition(e: EnumType, enumName: Name): void { + private renderEnumDefinition (e: EnumType, enumName: Name): void { this.startFile(enumName); this.emitLineOnce("import Foundation"); @@ -935,7 +959,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } else { this.emitBlockWithAccess(["enum ", enumName, protocolString], () => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("case ", name, ' = "', stringEscape(jsonName), '"'); + this.emitLine("case ", name, " = \"", stringEscape(jsonName), "\""); }); }); } @@ -943,13 +967,13 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.endFile(); } - private renderUnionDefinition(u: UnionType, unionName: Name): void { + private renderUnionDefinition (u: UnionType, unionName: Name): void { this.startFile(unionName); this.emitLineOnce("import Foundation"); this.ensureBlankLine(); - function sortBy(t: Type): string { + function sortBy (t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -986,12 +1010,14 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); if (t.kind === "bool" || t.kind === "integer") continue; renderUnionCase(t); } + if (maybeNull !== null) { this.emitBlock("if container.decodeNil()", () => { this.emitLine("self = .", this.nameForUnionMember(u, maybeNull)); this.emitLine("return"); }); } + this.emitDecodingError(unionName); }); this.ensureBlankLine(); @@ -1006,6 +1032,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.emitLine("case .", this.nameForUnionMember(u, maybeNull), ":"); this.indent(() => this.emitLine("try container.encodeNil()")); } + this.emitLine("}"); }); } @@ -1013,7 +1040,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.endFile(); } - private emitTopLevelMapAndArrayConvenienceInitializerExtensions(t: Type, name: Name): void { + private emitTopLevelMapAndArrayConvenienceInitializerExtensions (t: Type, name: Name): void { let extensionSource: Sourcelike; if (t instanceof ArrayType) { @@ -1031,12 +1058,12 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.ensureBlankLine(); this.emitBlock("init(_ json: String, using encoding: String.Encoding = .utf8) throws", () => { this.emitBlock("guard let data = json.data(using: encoding) else", () => { - this.emitLine(`throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)`); + this.emitLine("throw NSError(domain: \"JSONDecoding\", code: 0, userInfo: nil)"); }); this.emitLine("try self.init(data: data)"); }); this.ensureBlankLine(); - this.emitBlock(`init(fromURL url: URL) throws`, () => { + this.emitBlock("init(fromURL url: URL) throws", () => { this.emitLine("try self.init(data: try Data(contentsOf: url))"); }); this.ensureBlankLine(); @@ -1050,17 +1077,17 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } - private emitDecodingError(name: Name): void { + private emitDecodingError (name: Name): void { this.emitLine( "throw DecodingError.typeMismatch(", name, - '.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ', + ".self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Wrong type for ", name, - '"))' + "\"))", ); } - private emitSupportFunctions4 = (): void => { + private readonly emitSupportFunctions4 = (): void => { this.startFile("JSONSchemaSupport"); this.emitLineOnce("import Foundation"); @@ -1068,17 +1095,17 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.forEachTopLevel( "leading", (t: Type, name: Name) => this.renderTopLevelAlias(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); if (this._options.convenienceInitializers) { this.ensureBlankLine(); this.forEachTopLevel("leading-and-interposing", (t: Type, name: Name) => - this.emitTopLevelMapAndArrayConvenienceInitializerExtensions(t, name) + this.emitTopLevelMapAndArrayConvenienceInitializerExtensions(t, name), ); } - if ((!this._options.justTypes && this._options.convenienceInitializers) || this._options.alamofire) { + if (!this._options.justTypes && this._options.convenienceInitializers || this._options.alamofire) { this.ensureBlankLine(); this.emitMark("Helper functions for creating encoders and decoders", true); this.ensureBlankLine(); @@ -1103,6 +1130,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } else { this.emitLine(this.accessLevel, "class JSONNull: Codable, Hashable {"); } + this.ensureBlankLine(); this.emitMultiline(` public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool { return true @@ -1128,6 +1156,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } else { this.emitItem(" "); } + this.emitMultiline(`public init() {} public required init(from decoder: Decoder) throws { @@ -1143,6 +1172,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } }`); } + if (this._needAny) { this.ensureBlankLine(); this.emitMultiline(`class JSONCodingKey: CodingKey { @@ -1171,6 +1201,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } else { this.emitLine(this.accessLevel, "class JSONAny: Codable {"); } + this.ensureBlankLine(); this.emitMultiline(` ${this.accessLevel}let value: Any @@ -1369,7 +1400,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.endFile(); }; - private emitConvenienceMutator(c: ClassType, className: Name) { + private emitConvenienceMutator (c: ClassType, className: Name) { this.emitLine("func with("); this.indent(() => { this.forEachClassProperty(c, "none", (name, _, p, position) => { @@ -1378,7 +1409,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); ": ", this.swiftPropertyType(p), "? = nil", - position !== "only" && position !== "last" ? "," : "" + position !== "only" && position !== "last" ? "," : "", ); }); }); @@ -1392,7 +1423,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); name, " ?? self.", name, - position !== "only" && position !== "last" ? "," : "" + position !== "only" && position !== "last" ? "," : "", ); }); }); @@ -1400,11 +1431,11 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } - protected emitMark(line: Sourcelike, horizontalLine = false) { + protected emitMark (line: Sourcelike, horizontalLine = false) { this.emitLine("// MARK:", horizontalLine ? " - " : " ", line); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { if (this._options.multiFileOutput === false) { this.renderSingleFileHeaderComments(); } @@ -1413,7 +1444,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); "leading-and-interposing", (c: ClassType, className: Name) => this.renderClassDefinition(c, className), (e: EnumType, enumName: Name) => this.renderEnumDefinition(e, enumName), - (u: UnionType, unionName: Name) => this.renderUnionDefinition(u, unionName) + (u: UnionType, unionName: Name) => this.renderUnionDefinition(u, unionName), ); if (!this._options.justTypes) { @@ -1421,7 +1452,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } } - private emitAlamofireExtension() { + private emitAlamofireExtension () { this.ensureBlankLine(); this.emitBlockWithAccess("extension DataRequest", () => { this @@ -1450,11 +1481,11 @@ fileprivate func responseDecodable(queue: DispatchQueue? = nil, co name, "(queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse<", name, - ">) -> Void) -> Self" + ">) -> Void) -> Self", ], () => { - this.emitLine(`return responseDecodable(queue: queue, completionHandler: completionHandler)`); - } + this.emitLine("return responseDecodable(queue: queue, completionHandler: completionHandler)"); + }, ); }); }); diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts index 22a1b9bdd..2629cff39 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts @@ -1,9 +1,12 @@ import { arrayIntercalate } from "collection-utils"; -import { ArrayType, ClassProperty, EnumType, MapType, ObjectType, Type } from "../Type"; +import { type ClassProperty, type ObjectType, type Type } from "../Type"; +import { ArrayType, EnumType, MapType } from "../Type"; import { matchType } from "../TypeUtils"; -import { funPrefixNamer, Name, Namer } from "../Naming"; -import { RenderContext } from "../Renderer"; -import { BooleanOption, getOptionValues, Option, OptionValues } from "../RendererOptions"; +import { type Name, type Namer } from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { type Option, type OptionValues } from "../RendererOptions"; +import { BooleanOption, getOptionValues } from "../RendererOptions"; import { acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; import { allLowerWordStyle, @@ -13,57 +16,57 @@ import { isLetterOrUnderscore, splitIntoWords, stringEscape, - utf16StringEscape + utf16StringEscape, } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; import { legalizeName } from "./JavaScript"; -import { Sourcelike } from "../Source"; +import { type Sourcelike } from "../Source"; import { panic } from "../support/Support"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; export const typeScriptEffectSchemaOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false) + justSchema: new BooleanOption("just-schema", "Schema only", false), }; export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage { - protected getOptions(): Option[] { + protected getOptions (): Array> { return []; } - constructor( + constructor ( displayName: string = "TypeScript Effect Schema", names: string[] = ["typescript-effect-schema"], - extension: string = "ts" + extension: string = "ts", ) { super(displayName, names, extension); } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): TypeScriptEffectSchemaRenderer { return new TypeScriptEffectSchemaRenderer( this, renderContext, - getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues) + getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues), ); } } export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; } - protected nameStyle(original: string, upper: boolean): string { + protected nameStyle (original: string, upper: boolean): string { const acronyms = acronymStyle(AcronymStyleOptions.Camel); const words = splitIntoWords(original); return combineWords( @@ -74,48 +77,49 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); } - private importStatement(lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { + private importStatement (lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { return ["import ", lhs, " from ", moduleName, ";"]; } - protected emitImports(): void { + protected emitImports (): void { this.ensureBlankLine(); - this.emitLine(this.importStatement("* as S", '"@effect/schema/Schema"')); + this.emitLine(this.importStatement("* as S", "\"@effect/schema/Schema\"")); } - typeMapTypeForProperty(p: ClassProperty): Sourcelike { + typeMapTypeForProperty (p: ClassProperty): Sourcelike { const typeMap = this.typeMapTypeFor(p.type); return p.isOptional ? ["S.optional(", typeMap, ")"] : typeMap; } emittedObjects = new Set(); - typeMapTypeFor(t: Type, required: boolean = true): Sourcelike { + typeMapTypeFor (t: Type, required: boolean = true): Sourcelike { if (t.kind === "class" || t.kind === "object" || t.kind === "enum") { const name = this.nameForNamedType(t); if (this.emittedObjects.has(name)) { return [name]; } + return ["S.suspend(() => ", name, ")"]; } @@ -133,13 +137,13 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { _enumType => panic("Should already be handled."), unionType => { const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false) + this.typeMapTypeFor(type, false), ); return ["S.union(", ...arrayIntercalate(", ", children), ")"]; }, _transformedStringType => { return "S.string"; - } + }, ); if (required) { @@ -149,10 +153,10 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { return match; } - private emitObject(name: Name, t: ObjectType) { + private emitObject (name: Name, t: ObjectType) { this.emittedObjects.add(name); this.ensureBlankLine(); - this.emitLine("\nexport class ", name, " extends S.Class<", name, '>("', name, '")({'); + this.emitLine("\nexport class ", name, " extends S.Class<", name, ">(\"", name, "\")({"); this.indent(() => { this.forEachClassProperty(t, "none", (_, jsonName, property) => { this.emitLine(`"${utf16StringEscape(jsonName)}"`, ": ", this.typeMapTypeForProperty(property), ","); @@ -161,15 +165,15 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { this.emitLine("}) {}"); } - private emitEnum(e: EnumType, enumName: Name): void { + private emitEnum (e: EnumType, enumName: Name): void { this.emittedObjects.add(enumName); this.ensureBlankLine(); this.emitDescription(this.descriptionForType(e)); this.emitLine("\nexport const ", enumName, " = ", "S.literal("); this.indent(() => this.forEachEnumCase(e, "none", (_, jsonName) => { - this.emitLine('"', stringEscape(jsonName), '",'); - }) + this.emitLine("\"", stringEscape(jsonName), "\","); + }), ); this.emitLine(");"); if (!this._options.justSchema) { @@ -177,8 +181,8 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { } } - protected walkObjectNames(type: ObjectType) { - const names: Array = []; + protected walkObjectNames (type: ObjectType) { + const names: Name[] = []; const recurse = (type: Type) => { if (type.kind === "object" || type.kind === "class") { @@ -204,7 +208,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { return names; } - protected emitSchemas(): void { + protected emitSchemas (): void { this.ensureBlankLine(); this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => { @@ -249,7 +253,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { order.forEach(i => this.emitGatheredSource(this.gatherSource(() => this.emitObject(mapKey[i], mapValue[i])))); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } diff --git a/packages/quicktype-core/src/language/TypeScriptFlow.ts b/packages/quicktype-core/src/language/TypeScriptFlow.ts index f21202056..f3dcb0765 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow.ts @@ -1,20 +1,25 @@ -import { Type, ArrayType, UnionType, ClassType, EnumType } from "../Type"; +import { type Type, type ClassType} from "../Type"; +import { ArrayType, UnionType, EnumType } from "../Type"; import { matchType, nullableFromUnion, isNamedType } from "../TypeUtils"; import { utf16StringEscape, camelCase } from "../support/Strings"; -import { Sourcelike, modifySource, MultiWord, singleWord, parenIfNeeded, multiWord } from "../Source"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { BooleanOption, Option, OptionValues, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, type MultiWord} from "../Source"; +import { modifySource, singleWord, parenIfNeeded, multiWord } from "../Source"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { BooleanOption, getOptionValues } from "../RendererOptions"; +import { + type JavaScriptTypeAnnotations} from "./JavaScript"; import { javaScriptOptions, JavaScriptTargetLanguage, JavaScriptRenderer, - JavaScriptTypeAnnotations, - legalizeName + legalizeName, } from "./JavaScript"; import { defined, panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { RenderContext } from "../Renderer"; +import { type TargetLanguage } from "../TargetLanguage"; +import { type RenderContext } from "../Renderer"; import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; export const tsFlowOptions = Object.assign({}, javaScriptOptions, { @@ -26,9 +31,9 @@ export const tsFlowOptions = Object.assign({}, javaScriptOptions, { preferConstValues: new BooleanOption( "prefer-const-values", "Use string instead of enum for string enums with single value", - false + false, ), - readonly: new BooleanOption("readonly", "Use readonly type members", false) + readonly: new BooleanOption("readonly", "Use readonly type members", false), }); const tsFlowTypeAnnotations = { @@ -37,11 +42,11 @@ const tsFlowTypeAnnotations = { anyMap: ": { [k: string]: any }", string: ": string", stringArray: ": string[]", - boolean: ": boolean" + boolean: ": boolean", }; export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetLanguage { - protected getOptions(): Option[] { + protected getOptions (): Array> { return [ tsFlowOptions.justTypes, tsFlowOptions.nicePropertyNames, @@ -54,34 +59,34 @@ export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetL tsFlowOptions.preferUnions, tsFlowOptions.preferTypes, tsFlowOptions.preferConstValues, - tsFlowOptions.readonly + tsFlowOptions.readonly, ]; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - protected abstract makeRenderer( + protected abstract makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, } ): JavaScriptRenderer; } export class TypeScriptTargetLanguage extends TypeScriptFlowBaseTargetLanguage { - constructor() { + constructor () { super("TypeScript", ["typescript", "ts", "tsx"], "ts"); } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): TypeScriptRenderer { return new TypeScriptRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); } } -function quotePropertyName(original: string): string { +function quotePropertyName (original: string): string { const escaped = utf16StringEscape(original); const quoted = `"${escaped}"`; @@ -99,15 +104,15 @@ function quotePropertyName(original: string): string { } export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _tsFlowOptions: OptionValues + protected readonly _tsFlowOptions: OptionValues, ) { super(targetLanguage, renderContext, _tsFlowOptions); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { if (this._tsFlowOptions.nicePropertyNames) { return funPrefixNamer("properties", s => this.nameStyle(s, false)); } else { @@ -115,14 +120,16 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } } - protected sourceFor(t: Type): MultiWord { + protected sourceFor (t: Type): MultiWord { if (this._tsFlowOptions.preferConstValues && t.kind === "enum" && t instanceof EnumType && t.cases.size === 1) { const item = t.cases.values().next().value; return singleWord(`"${utf16StringEscape(item)}"`); } - if (["class", "object", "enum"].indexOf(t.kind) >= 0) { + + if (["class", "object", "enum"].includes(t.kind)) { return singleWord(this.nameForNamedType(t)); } + return matchType( t, _anyType => singleWord("any"), @@ -134,7 +141,7 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { arrayType => { const itemType = this.sourceFor(arrayType.items); if ( - (arrayType.items instanceof UnionType && !this._tsFlowOptions.declareUnions) || + arrayType.items instanceof UnionType && !this._tsFlowOptions.declareUnions || arrayType.items instanceof ArrayType ) { return singleWord(["Array<", itemType.source, ">"]); @@ -157,16 +164,17 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { if (transformedStringType.kind === "date-time") { return singleWord("Date"); } + return singleWord("string"); - } + }, ); } - protected abstract emitEnum(e: EnumType, enumName: Name): void; + protected abstract emitEnum (e: EnumType, enumName: Name): void; - protected abstract emitClassBlock(c: ClassType, className: Name): void; + protected abstract emitClassBlock (c: ClassType, className: Name): void; - protected emitClassBlockBody(c: ClassType): void { + protected emitClassBlockBody (c: ClassType): void { this.emitPropertyTable(c, (name, _jsonName, p) => { const t = p.type; @@ -179,7 +187,7 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { return [ [propertyName, p.isOptional ? "?" : "", ": "], - [this.sourceFor(t).source, ";"] + [this.sourceFor(t).source, ";"], ]; }); @@ -189,12 +197,12 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } } - private emitClass(c: ClassType, className: Name) { + private emitClass (c: ClassType, className: Name) { this.emitDescription(this.descriptionForType(c)); this.emitClassBlock(c, className); } - emitUnion(u: UnionType, unionName: Name) { + emitUnion (u: UnionType, unionName: Name) { if (!this._tsFlowOptions.declareUnions) { return; } @@ -205,54 +213,54 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { this.emitLine("export type ", unionName, " = ", children.source, ";"); } - protected emitTypes(): void { + protected emitTypes (): void { this.forEachNamedType( "leading-and-interposing", (c: ClassType, n: Name) => this.emitClass(c, n), (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n) + (u, n) => this.emitUnion(u, n), ); } - protected emitUsageComments(): void { + protected emitUsageComments (): void { if (this._tsFlowOptions.justTypes) return; super.emitUsageComments(); } - protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { + protected deserializerFunctionLine (t: Type, name: Name): Sourcelike { const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["function to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; } - protected serializerFunctionLine(t: Type, name: Name): Sourcelike { + protected serializerFunctionLine (t: Type, name: Name): Sourcelike { const camelCaseName = modifySource(camelCase, name); const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["function ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; } - protected get moduleLine(): string | undefined { + protected get moduleLine (): string | undefined { return undefined; } - protected get castFunctionLines(): [string, string] { + protected get castFunctionLines (): [string, string] { return ["function cast(val: any, typ: any): T", "function uncast(val: T, typ: any): any"]; } - protected get typeAnnotations(): JavaScriptTypeAnnotations { + protected get typeAnnotations (): JavaScriptTypeAnnotations { throw new Error("not implemented"); } - protected emitConvertModule(): void { + protected emitConvertModule (): void { if (this._tsFlowOptions.justTypes) return; super.emitConvertModule(); } - protected emitConvertModuleHelpers(): void { + protected emitConvertModuleHelpers (): void { if (this._tsFlowOptions.justTypes) return; super.emitConvertModuleHelpers(); } - protected emitModuleExports(): void { + protected emitModuleExports (): void { if (this._tsFlowOptions.justTypes) { return; } else { @@ -262,46 +270,46 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return ["Array", "Date"]; } - protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { + protected deserializerFunctionLine (t: Type, name: Name): Sourcelike { const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["public static to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; } - protected serializerFunctionLine(t: Type, name: Name): Sourcelike { + protected serializerFunctionLine (t: Type, name: Name): Sourcelike { const camelCaseName = modifySource(camelCase, name); const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["public static ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; } - protected get moduleLine(): string | undefined { + protected get moduleLine (): string | undefined { return "export class Convert"; } - protected get typeAnnotations(): JavaScriptTypeAnnotations { + protected get typeAnnotations (): JavaScriptTypeAnnotations { return Object.assign({ never: ": never" }, tsFlowTypeAnnotations); } - protected emitModuleExports(): void { + protected emitModuleExports (): void { return; } - protected emitUsageImportComment(): void { + protected emitUsageImportComment (): void { const topLevelNames: Sourcelike[] = []; this.forEachTopLevel( "none", (_t, name) => { topLevelNames.push(", ", name); }, - isNamedType + isNamedType, ); - this.emitLine("// import { Convert", topLevelNames, ' } from "./file";'); + this.emitLine("// import { Convert", topLevelNames, " } from \"./file\";"); } - protected emitEnum(e: EnumType, enumName: Name): void { + protected emitEnum (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); // enums with only one value are emitted as constants @@ -314,6 +322,7 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { items += `"${utf16StringEscape(item)}"`; return; } + items += ` | "${utf16StringEscape(item)}"`; }); this.emitLine("export type ", enumName, " = ", items, ";"); @@ -326,7 +335,7 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { } } - protected emitClassBlock(c: ClassType, className: Name): void { + protected emitClassBlock (c: ClassType, className: Name): void { this.emitBlock( this._tsFlowOptions.preferTypes ? ["export type ", className, " = "] @@ -334,36 +343,36 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { "", () => { this.emitClassBlockBody(c); - } + }, ); } } export class FlowTargetLanguage extends TypeScriptFlowBaseTargetLanguage { - constructor() { + constructor () { super("Flow", ["flow"], "js"); } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): FlowRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): FlowRenderer { return new FlowRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); } } export class FlowRenderer extends TypeScriptFlowBaseRenderer { - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; } - protected get typeAnnotations(): JavaScriptTypeAnnotations { + protected get typeAnnotations (): JavaScriptTypeAnnotations { return Object.assign({ never: "" }, tsFlowTypeAnnotations); } - protected emitEnum(e: EnumType, enumName: Name): void { + protected emitEnum (e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); const lines: string[][] = []; this.forEachEnumCase(e, "none", (_, jsonName) => { const maybeOr = lines.length === 0 ? " " : "| "; - lines.push([maybeOr, '"', utf16StringEscape(jsonName), '"']); + lines.push([maybeOr, "\"", utf16StringEscape(jsonName), "\""]); }); defined(lines[lines.length - 1]).push(";"); @@ -375,13 +384,13 @@ export class FlowRenderer extends TypeScriptFlowBaseRenderer { }); } - protected emitClassBlock(c: ClassType, className: Name): void { + protected emitClassBlock (c: ClassType, className: Name): void { this.emitBlock(["export type ", className, " = "], ";", () => { this.emitClassBlockBody(c); }); } - protected emitSourceStructure() { + protected emitSourceStructure () { this.emitLine("// @flow"); this.ensureBlankLine(); super.emitSourceStructure(); diff --git a/packages/quicktype-core/src/language/TypeScriptZod.ts b/packages/quicktype-core/src/language/TypeScriptZod.ts index b2197624a..75b9e7f96 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod.ts @@ -1,21 +1,25 @@ -import { StringTypeMapping } from "TypeBuilder"; +import { type StringTypeMapping } from "TypeBuilder"; import { arrayIntercalate } from "collection-utils"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { Name, Namer, funPrefixNamer } from "../Naming"; -import { RenderContext } from "../Renderer"; -import { BooleanOption, Option, OptionValues, getOptionValues } from "../RendererOptions"; -import { Sourcelike } from "../Source"; +import { type Name, type Namer} from "../Naming"; +import { funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { type Option, type OptionValues} from "../RendererOptions"; +import { BooleanOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike } from "../Source"; import { TargetLanguage } from "../TargetLanguage"; +import { + type ClassProperty, + type EnumType, + type PrimitiveStringTypeKind, + type TransformedStringTypeKind, + type Type, +} from "../Type"; import { ArrayType, - ClassProperty, ClassType, - EnumType, ObjectType, - PrimitiveStringTypeKind, SetOperationType, - TransformedStringTypeKind, - Type } from "../Type"; import { matchType } from "../TypeUtils"; import { AcronymStyleOptions, acronymStyle } from "../support/Acronyms"; @@ -27,65 +31,65 @@ import { isLetterOrUnderscore, splitIntoWords, stringEscape, - utf16StringEscape + utf16StringEscape, } from "../support/Strings"; import { panic } from "../support/Support"; import { legalizeName } from "./JavaScript"; export const typeScriptZodOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false) + justSchema: new BooleanOption("just-schema", "Schema only", false), }; export class TypeScriptZodTargetLanguage extends TargetLanguage { - protected getOptions(): Option[] { + protected getOptions (): Array> { return []; } - constructor( + constructor ( displayName: string = "TypeScript Zod", names: string[] = ["typescript-zod"], - extension: string = "ts" + extension: string = "ts", ) { super(displayName, names, extension); } - get stringTypeMapping(): StringTypeMapping { + get stringTypeMapping (): StringTypeMapping { const mapping: Map = new Map(); const dateTimeType = "date-time"; mapping.set("date-time", dateTimeType); return mapping; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - protected makeRenderer( + protected makeRenderer ( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: { [name: string]: any, }, ): TypeScriptZodRenderer { return new TypeScriptZodRenderer( this, renderContext, - getOptionValues(typeScriptZodOptions, untypedOptionValues) + getOptionValues(typeScriptZodOptions, untypedOptionValues), ); } } export class TypeScriptZodRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues + protected readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; } - protected nameStyle(original: string, upper: boolean): string { + protected nameStyle (original: string, upper: boolean): string { const acronyms = acronymStyle(AcronymStyleOptions.Camel); const words = splitIntoWords(original); return combineWords( @@ -96,42 +100,42 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); } - protected importStatement(lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { + protected importStatement (lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { return ["import ", lhs, " from ", moduleName, ";"]; } - protected emitImports(): void { + protected emitImports (): void { this.ensureBlankLine(); - this.emitLine(this.importStatement("* as z", '"zod"')); + this.emitLine(this.importStatement("* as z", "\"zod\"")); } - protected typeMapTypeForProperty(p: ClassProperty): Sourcelike { + protected typeMapTypeForProperty (p: ClassProperty): Sourcelike { const typeMap = this.typeMapTypeFor(p.type); return p.isOptional ? [typeMap, ".optional()"] : typeMap; } - protected typeMapTypeFor(t: Type, required: boolean = true): Sourcelike { - if (["class", "object", "enum"].indexOf(t.kind) >= 0) { + protected typeMapTypeFor (t: Type, required: boolean = true): Sourcelike { + if (["class", "object", "enum"].includes(t.kind)) { return [this.nameForNamedType(t), "Schema"]; } @@ -149,7 +153,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { _enumType => panic("Should already be handled."), unionType => { const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false) + this.typeMapTypeFor(type, false), ); return ["z.union([", ...arrayIntercalate(", ", children), "])"]; }, @@ -157,8 +161,9 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { if (_transformedStringType.kind === "date-time") { return "z.coerce.date()"; } + return "z.string()"; - } + }, ); if (required) { @@ -168,7 +173,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { return match; } - protected emitObject(name: Name, t: ObjectType) { + protected emitObject (name: Name, t: ObjectType) { this.ensureBlankLine(); this.emitLine("\nexport const ", name, "Schema = ", "z.object({"); this.indent(() => { @@ -182,14 +187,14 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { } } - protected emitEnum(e: EnumType, enumName: Name): void { + protected emitEnum (e: EnumType, enumName: Name): void { this.ensureBlankLine(); this.emitDescription(this.descriptionForType(e)); this.emitLine("\nexport const ", enumName, "Schema = ", "z.enum(["); this.indent(() => this.forEachEnumCase(e, "none", (_, jsonName) => { - this.emitLine('"', stringEscape(jsonName), '",'); - }) + this.emitLine("\"", stringEscape(jsonName), "\","); + }), ); this.emitLine("]);"); if (!this._options.justSchema) { @@ -204,46 +209,47 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { * Primitive types don't need defining and enums are output before other types, hence, * these are ignored. */ - static extractUnderlyingTyperefs(type: Type): number[] { + static extractUnderlyingTyperefs (type: Type): number[] { let typeRefs: number[] = []; - //Ignore enums and primitives + // Ignore enums and primitives if (!type.isPrimitive() && type.kind != "enum") { - //need to extract constituent types for unions and intersections (which both extend SetOperationType) - //and can ignore the union/intersection itself + // need to extract constituent types for unions and intersections (which both extend SetOperationType) + // and can ignore the union/intersection itself if (type instanceof SetOperationType) { (type as SetOperationType).members.forEach(member => { - //recurse as the underlying type could itself be a union, instersection or array etc. + // recurse as the underlying type could itself be a union, instersection or array etc. typeRefs.push(...TypeScriptZodRenderer.extractUnderlyingTyperefs(member)); }); } - //need to extract additional properties for object, class and map types (which all extend ObjectType) + // need to extract additional properties for object, class and map types (which all extend ObjectType) if (type instanceof ObjectType) { const addType = (type as ObjectType).getAdditionalProperties(); if (addType) { - //recurse as the underlying type could itself be a union, instersection or array etc. + // recurse as the underlying type could itself be a union, instersection or array etc. typeRefs.push(...TypeScriptZodRenderer.extractUnderlyingTyperefs(addType)); } } - //need to extract items types for ArrayType + // need to extract items types for ArrayType if (type instanceof ArrayType) { const itemsType = (type as ArrayType).items; if (itemsType) { - //recurse as the underlying type could itself be a union, instersection or array etc. + // recurse as the underlying type could itself be a union, instersection or array etc. typeRefs.push(...TypeScriptZodRenderer.extractUnderlyingTyperefs(itemsType)); } } - //Finally return the reference to a class as that will need to be defined (where objects, maps, unions, intersections and arrays do not) + // Finally return the reference to a class as that will need to be defined (where objects, maps, unions, intersections and arrays do not) if (type instanceof ClassType) { typeRefs.push(type.typeRef); } } + return typeRefs; } - protected emitSchemas(): void { + protected emitSchemas (): void { this.ensureBlankLine(); this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => { @@ -275,15 +281,15 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { mapChildTypeRefs.push(childTypeRefs); }); - //Items to process on this pass + // Items to process on this pass let indices: number[] = []; mapType.forEach((_, index) => { indices.push(index); }); - //items to process on the next pass + // items to process on the next pass let deferredIndices: number[] = []; - //defensive: make sure we don't loop forever, even complex sets shouldn't require many passes + // defensive: make sure we don't loop forever, even complex sets shouldn't require many passes const MAX_PASSES = 999; let passNum = 0; do { @@ -293,11 +299,11 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { let foundAllChildren = true; childTypeRefs.forEach(childRef => { - //defensive: first check if there is a definition for the referenced type (there should be) - if (mapTypeRef.indexOf(childRef) > -1) { + // defensive: first check if there is a definition for the referenced type (there should be) + if (mapTypeRef.includes(childRef)) { let found = false; // find this childs's ordinal, if it has already been added - //faster to go through what we've defined so far than all definitions + // faster to go through what we've defined so far than all definitions for (let j = 0; j < order.length; j++) { const childIndex = order[j]; if (mapTypeRef[childIndex] === childRef) { @@ -305,10 +311,11 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { break; } } + foundAllChildren = foundAllChildren && found; } else { console.error( - "A child type reference was not found amongst all Object definitions! TypeRef: " + childRef + "A child type reference was not found amongst all Object definitions! TypeRef: " + childRef, ); } }); @@ -317,7 +324,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { // insert index into order as we are safe to define this type order.push(index); } else { - //defer to a subsequent pass as we need to define other types + // defer to a subsequent pass as we need to define other types deferredIndices.push(index); } }); @@ -326,7 +333,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { passNum++; if (passNum > MAX_PASSES) { - //giving up + // giving up order.push(...deferredIndices); console.warn("Exceeded maximum number of passes when determining output order, output may contain forward references"); } @@ -336,7 +343,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { order.forEach(i => this.emitGatheredSource(this.gatherSource(() => this.emitObject(mapName[i], mapType[i])))); } - protected emitSourceStructure(): void { + protected emitSourceStructure (): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } diff --git a/packages/quicktype-core/src/language/ruby/index.ts b/packages/quicktype-core/src/language/ruby/index.ts index 383bdd5ae..42868baa7 100644 --- a/packages/quicktype-core/src/language/ruby/index.ts +++ b/packages/quicktype-core/src/language/ruby/index.ts @@ -1,16 +1,21 @@ import unicode from "unicode-properties"; -import { Sourcelike, modifySource } from "../../Source"; -import { Namer, Name } from "../../Naming"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Sourcelike} from "../../Source"; +import { modifySource } from "../../Source"; +import { type Name } from "../../Naming"; +import { Namer } from "../../Naming"; +import { type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { ConvenienceRenderer } from "../../ConvenienceRenderer"; import { TargetLanguage } from "../../TargetLanguage"; -import { Option, BooleanOption, EnumOption, OptionValues, getOptionValues, StringOption } from "../../RendererOptions"; +import { type Option, type OptionValues} from "../../RendererOptions"; +import { BooleanOption, EnumOption, getOptionValues, StringOption } from "../../RendererOptions"; import * as keywords from "./keywords"; const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); -import { Type, EnumType, ClassType, UnionType, ArrayType, MapType, ClassProperty } from "../../Type"; +import { type Type, type EnumType, type UnionType, type ClassProperty } from "../../Type"; +import { ClassType, ArrayType, MapType } from "../../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; import { @@ -25,20 +30,20 @@ import { escapeNonPrintableMapper, intToHex, snakeCase, - isLetterOrUnderscore + isLetterOrUnderscore, } from "../../support/Strings"; -import { RenderContext } from "../../Renderer"; +import { type RenderContext } from "../../Renderer"; -function unicodeEscape(codePoint: number): string { +function unicodeEscape (codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; } const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); export enum Strictness { - Strict = "Strict::", Coercible = "Coercible::", - None = "Types::" + None = "Types::", + Strict = "Strict::" } export const rubyOptions = { @@ -46,46 +51,47 @@ export const rubyOptions = { strictness: new EnumOption("strictness", "Type strictness", [ ["strict", Strictness.Strict], ["coercible", Strictness.Coercible], - ["none", Strictness.None] + ["none", Strictness.None], ]), - namespace: new StringOption("namespace", "Specify a wrapping Namespace", "NAME", "", "secondary") + namespace: new StringOption("namespace", "Specify a wrapping Namespace", "NAME", "", "secondary"), }; export class RubyTargetLanguage extends TargetLanguage { - constructor() { + constructor () { super("Ruby", ["ruby"], "rb"); } - protected getOptions(): Option[] { + protected getOptions (): Array> { return [rubyOptions.justTypes, rubyOptions.strictness, rubyOptions.namespace]; } - get supportsOptionalClassProperties(): boolean { + get supportsOptionalClassProperties (): boolean { return true; } - protected get defaultIndentation(): string { + protected get defaultIndentation (): string { return " "; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): RubyRenderer { + protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): RubyRenderer { return new RubyRenderer(this, renderContext, getOptionValues(rubyOptions, untypedOptionValues)); } } const isStartCharacter = isLetterOrUnderscore; -function isPartCharacter(utf16Unit: number): boolean { +function isPartCharacter (utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } const legalizeName = legalizeCharacters(isPartCharacter); -function simpleNameStyle(original: string, uppercase: boolean): string { +function simpleNameStyle (original: string, uppercase: boolean): string { if (/^[0-9]+$/.test(original)) { original = original + "N"; } + const words = splitIntoWords(original); return combineWords( words, @@ -95,11 +101,11 @@ function simpleNameStyle(original: string, uppercase: boolean): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } -function memberNameStyle(original: string): string { +function memberNameStyle (original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -109,56 +115,56 @@ function memberNameStyle(original: string): string { allLowerWordStyle, allLowerWordStyle, "_", - isStartCharacter + isStartCharacter, ); } export class RubyRenderer extends ConvenienceRenderer { - constructor( + constructor ( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } - protected get commentLineStart(): string { + protected get commentLineStart (): string { return "# "; } - protected get needsTypeDeclarationBeforeUse(): boolean { + protected get needsTypeDeclarationBeforeUse (): boolean { return true; } - protected canBeForwardDeclared(t: Type): boolean { + protected canBeForwardDeclared (t: Type): boolean { return "class" === t.kind; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace (): string[] { return keywords.globals.concat(["Types", "JSON", "Dry", "Constructor", "Self"]); } - protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties (_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { return { names: forbiddenForObjectProperties, includeGlobalForbidden: true }; } - protected makeNamedTypeNamer(): Namer { + protected makeNamedTypeNamer (): Namer { return new Namer("types", n => simpleNameStyle(n, true), []); } - protected namerForObjectProperty(): Namer { + protected namerForObjectProperty (): Namer { return new Namer("properties", memberNameStyle, []); } - protected makeUnionMemberNamer(): Namer { + protected makeUnionMemberNamer (): Namer { return new Namer("properties", memberNameStyle, []); } - protected makeEnumCaseNamer(): Namer { + protected makeEnumCaseNamer (): Namer { return new Namer("enum-cases", n => simpleNameStyle(n, true), []); } - private dryType(t: Type, isOptional = false): Sourcelike { + private dryType (t: Type, isOptional = false): Sourcelike { const optional = isOptional ? ".optional" : ""; return matchType( t, @@ -177,12 +183,13 @@ export class RubyRenderer extends ConvenienceRenderer { if (nullable !== null) { return [this.dryType(nullable), ".optional"]; } + return ["Types.Instance(", this.nameForNamedType(unionType), ")", optional]; - } + }, ); } - private exampleUse(t: Type, exp: Sourcelike, depth = 6, optional = false): Sourcelike { + private exampleUse (t: Type, exp: Sourcelike, depth = 6, optional = false): Sourcelike { if (depth-- <= 0) { return exp; } @@ -199,9 +206,9 @@ export class RubyRenderer extends ConvenienceRenderer { _stringType => exp, arrayType => this.exampleUse(arrayType.items, [exp, safeNav, ".first"], depth), classType => { - let info: { name: Name; prop: ClassProperty } | undefined; + let info: { name: Name, prop: ClassProperty, } | undefined; this.forEachClassProperty(classType, "none", (name, _json, prop) => { - if (["class", "map", "array"].indexOf(prop.type.kind) >= 0) { + if (["class", "map", "array"].includes(prop.type.kind)) { info = { name, prop }; } else if (info === undefined) { info = { name, prop }; @@ -210,9 +217,10 @@ export class RubyRenderer extends ConvenienceRenderer { if (info !== undefined) { return this.exampleUse(info.prop.type, [exp, safeNav, ".", info.name], depth, info.prop.isOptional); } + return exp; }, - mapType => this.exampleUse(mapType.values, [exp, safeNav, `["…"]`], depth), + mapType => this.exampleUse(mapType.values, [exp, safeNav, "[\"…\"]"], depth), enumType => { let name: Name | undefined; // FIXME: This is a terrible way to get the first enum case name. @@ -224,23 +232,26 @@ export class RubyRenderer extends ConvenienceRenderer { if (name !== undefined) { return [exp, " == ", this.nameForNamedType(enumType), "::", name]; } + return exp; }, unionType => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { - if (["class", "map", "array"].indexOf(nullable.kind) >= 0) { + if (["class", "map", "array"].includes(nullable.kind)) { return this.exampleUse(nullable, exp, depth, true); } + return [exp, ".nil?"]; } + return exp; - } + }, ); } - private jsonSample(t: Type): Sourcelike { - function inner() { + private jsonSample (t: Type): Sourcelike { + function inner () { if (t instanceof ArrayType) { return "[…]"; } else if (t instanceof MapType) { @@ -251,10 +262,11 @@ export class RubyRenderer extends ConvenienceRenderer { return "…"; } } + return `"${inner()}"`; } - private fromDynamic(t: Type, e: Sourcelike, optional = false, castPrimitives = false): Sourcelike { + private fromDynamic (t: Type, e: Sourcelike, optional = false, castPrimitives = false): Sourcelike { const primitiveCast = [this.dryType(t, optional), "[", e, "]"]; const primitive = castPrimitives ? primitiveCast : e; const safeAccess = optional ? "&" : ""; @@ -278,7 +290,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.fromDynamic(mapType.values, "v", false, true), "] }", safeAccess, - ".to_h" + ".to_h", ], enumType => { const expression = ["Types::", this.nameForNamedType(enumType), "[", e, "]"]; @@ -289,16 +301,18 @@ export class RubyRenderer extends ConvenienceRenderer { if (nullable !== null) { return this.fromDynamic(nullable, e, true); } + const expression = [this.nameForNamedType(unionType), ".from_dynamic!(", e, ")"]; return optional ? [e, " ? ", expression, " : nil"] : expression; - } + }, ); } - private toDynamic(t: Type, e: Sourcelike, optional = false): Sourcelike { + private toDynamic (t: Type, e: Sourcelike, optional = false): Sourcelike { if (this.marshalsImplicitlyToDynamic(t)) { return e; } + return matchType( t, _anyType => e, @@ -316,15 +330,17 @@ export class RubyRenderer extends ConvenienceRenderer { if (nullable !== null) { return this.toDynamic(nullable, e, true); } + if (this.marshalsImplicitlyToDynamic(unionType)) { return e; } + return [e, optional ? "&" : "", ".to_dynamic"]; - } + }, ); } - private marshalsImplicitlyToDynamic(t: Type): boolean { + private marshalsImplicitlyToDynamic (t: Type): boolean { return matchType( t, _anyType => true, @@ -342,15 +358,16 @@ export class RubyRenderer extends ConvenienceRenderer { if (nullable !== null) { return this.marshalsImplicitlyToDynamic(nullable); } + return false; - } + }, ); } // This is only to be used to allow class properties to possibly // marshal implicitly. They are allowed to do this because they will // be checked in Dry::Struct.new - private propertyTypeMarshalsImplicitlyFromDynamic(t: Type): boolean { + private propertyTypeMarshalsImplicitlyFromDynamic (t: Type): boolean { return matchType( t, _anyType => true, @@ -369,18 +386,19 @@ export class RubyRenderer extends ConvenienceRenderer { if (nullable !== null) { return this.propertyTypeMarshalsImplicitlyFromDynamic(nullable); } + return false; - } + }, ); } - private emitBlock(source: Sourcelike, emit: () => void) { + private emitBlock (source: Sourcelike, emit: () => void) { this.emitLine(source); this.indent(emit); this.emitLine("end"); } - private emitModule(emit: () => void) { + private emitModule (emit: () => void) { const emitModuleInner = (moduleName: string) => { const [firstModule, ...subModules] = moduleName.split("::"); if (subModules.length > 0) { @@ -391,6 +409,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitBlock(["module ", moduleName], emit); } }; + if (this._options.namespace !== undefined && this._options.namespace !== "") { emitModuleInner(this._options.namespace); } else { @@ -398,7 +417,7 @@ export class RubyRenderer extends ConvenienceRenderer { } } - private emitClass(c: ClassType, className: Name) { + private emitClass (c: ClassType, className: Name) { this.emitDescription(this.descriptionForType(c)); this.emitBlock(["class ", className, " < Dry::Struct"], () => { let table: Sourcelike[][] = []; @@ -408,13 +427,14 @@ export class RubyRenderer extends ConvenienceRenderer { const description = this.descriptionForClassProperty(c, jsonName); const attribute = [ ["attribute :", name, ","], - [" ", this.dryType(p.type), p.isOptional ? ".optional" : ""] + [" ", this.dryType(p.type), p.isOptional ? ".optional" : ""], ]; if (description !== undefined) { if (table.length > 0) { this.emitTable(table); table = []; } + this.ensureBlankLine(); this.emitDescriptionBlock(description); this.emitLine(attribute); @@ -442,20 +462,20 @@ export class RubyRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const dynamic = p.isOptional ? // If key is not found in hash, this will be nil - `d["${stringEscape(jsonName)}"]` + `d["${stringEscape(jsonName)}"]` : // This will raise a runtime error if the key is not found in the hash - `d.fetch("${stringEscape(jsonName)}")`; + `d.fetch("${stringEscape(jsonName)}")`; if (this.propertyTypeMarshalsImplicitlyFromDynamic(p.type)) { inits.push([ [name, ": "], - [dynamic, ","] + [dynamic, ","], ]); } else { const expression = this.fromDynamic(p.type, dynamic, p.isOptional); inits.push([ [name, ": "], - [expression, ","] + [expression, ","], ]); } }); @@ -489,7 +509,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitEnum(e: EnumType, enumName: Name) { + private emitEnum (e: EnumType, enumName: Name) { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["module ", enumName], () => { const table: Sourcelike[][] = []; @@ -500,7 +520,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitUnion(u: UnionType, unionName: Name) { + private emitUnion (u: UnionType, unionName: Name) { this.emitDescription(this.descriptionForType(u)); this.emitBlock(["class ", unionName, " < Dry::Struct"], () => { const table: Sourcelike[][] = []; @@ -537,7 +557,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitLine("end"); } }); - this.emitLine(`raise "Invalid union"`); + this.emitLine("raise \"Invalid union\""); }); this.ensureBlankLine(); @@ -561,6 +581,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitLine("nil"); }); } + this.emitLine("end"); }); @@ -571,7 +592,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitTypesModule() { + private emitTypesModule () { this.emitBlock(["module Types"], () => { this.emitLine("include Dry.Types(default: :nominal)"); @@ -586,20 +607,21 @@ export class RubyRenderer extends ConvenienceRenderer { bool: has.bool || t.kind === "bool", hash: has.hash || t.kind === "map" || t.kind === "class", string: has.string || t.kind === "string" || t.kind === "enum", - double: has.double || t.kind === "double" + double: has.double || t.kind === "double", }; }); if (has.int) declarations.push([["Integer"], [` = ${this._options.strictness}Integer`]]); if (this._options.strictness === Strictness.Strict) { if (has.nil) declarations.push([["Nil"], [` = ${this._options.strictness}Nil`]]); } + if (has.bool) declarations.push([["Bool"], [` = ${this._options.strictness}Bool`]]); if (has.hash) declarations.push([["Hash"], [` = ${this._options.strictness}Hash`]]); if (has.string) declarations.push([["String"], [` = ${this._options.strictness}String`]]); if (has.double) declarations.push([ ["Double"], - [` = ${this._options.strictness}Float | ${this._options.strictness}Integer`] + [` = ${this._options.strictness}Float | ${this._options.strictness}Integer`], ]); } @@ -618,7 +640,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - protected emitSourceStructure() { + protected emitSourceStructure () { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else if (!this._options.justTypes) { @@ -635,6 +657,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); this.emitLine("# If from_json! succeeds, the value returned matches the schema."); } + this.ensureBlankLine(); this.emitLine("require 'json'"); @@ -659,7 +682,7 @@ export class RubyRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClass(c, n), (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n) + (u, n) => this.emitUnion(u, n), ); if (!this._options.justTypes) { @@ -679,7 +702,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitLine( self, " = ", - this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") + this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)"), ); this.emitBlock([self, ".define_singleton_method(:to_json) do"], () => { this.emitLine("JSON.generate(", this.toDynamic(topLevel, "self"), ")"); @@ -687,7 +710,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitLine(self); } else { this.emitLine( - this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") + this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)"), ); } }); @@ -698,7 +721,7 @@ export class RubyRenderer extends ConvenienceRenderer { classDeclaration(); }); }, - t => this.namedTypeToNameForTopLevel(t) === undefined + t => this.namedTypeToNameForTopLevel(t) === undefined, ); } }); diff --git a/packages/quicktype-core/src/language/ruby/keywords.ts b/packages/quicktype-core/src/language/ruby/keywords.ts index e01c14b5f..0229d9044 100644 --- a/packages/quicktype-core/src/language/ruby/keywords.ts +++ b/packages/quicktype-core/src/language/ruby/keywords.ts @@ -39,7 +39,7 @@ export const keywords = [ "until", "when", "while", - "yield" + "yield", ]; const globalClasses = [ @@ -133,7 +133,7 @@ const globalClasses = [ "Undefined", "UnicodeNormalize", "Warning", - "ZeroDivisionError" + "ZeroDivisionError", ]; const kernel = [ @@ -286,7 +286,7 @@ const kernel = [ "untrace_var", "untrust", "untrusted?", - "warn" + "warn", ]; export const globals = kernel.concat(globalClasses); @@ -355,5 +355,5 @@ export const reservedProperties = [ "undef", "untrust", "while", - "with" + "with", ]; diff --git a/packages/quicktype-core/src/rewrites/CombineClasses.ts b/packages/quicktype-core/src/rewrites/CombineClasses.ts index 1f350644e..a89826f7c 100644 --- a/packages/quicktype-core/src/rewrites/CombineClasses.ts +++ b/packages/quicktype-core/src/rewrites/CombineClasses.ts @@ -1,27 +1,28 @@ -import { ClassType, Type, ClassProperty, setOperationCasesEqual } from "../Type"; +import { type Type, type ClassProperty} from "../Type"; +import { ClassType, setOperationCasesEqual } from "../Type"; import { nonNullTypeCases, combineTypeAttributesOfTypes } from "../TypeUtils"; -import { GraphRewriteBuilder } from "../GraphRewriting"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; import { assert, panic } from "../support/Support"; -import { TypeGraph, TypeRef } from "../TypeGraph"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; import { unifyTypes, unionBuilderForUnification } from "../UnifyClasses"; -import { RunContext } from "../Run"; +import { type RunContext } from "../Run"; const REQUIRED_OVERLAP = 3 / 4; -type Clique = { +interface Clique { members: ClassType[]; prototypes: ClassType[]; -}; +} // FIXME: Allow some type combinations to unify, like different enums, // enums with strings, integers with doubles, maps with objects of // the correct type. -function typeSetsCanBeCombined(s1: Iterable, s2: Iterable): boolean { +function typeSetsCanBeCombined (s1: Iterable, s2: Iterable): boolean { return setOperationCasesEqual(s1, s2, true, (a, b) => a.structurallyCompatible(b, true)); } -function canBeCombined(c1: ClassType, c2: ClassType, onlyWithSameProperties: boolean): boolean { +function canBeCombined (c1: ClassType, c2: ClassType, onlyWithSameProperties: boolean): boolean { const p1 = c1.getProperties(); const p2 = c2.getProperties(); if (onlyWithSameProperties) { @@ -63,6 +64,7 @@ function canBeCombined(c1: ClassType, c2: ClassType, onlyWithSameProperties: boo if (faults > maxFaults) break; } } + if (faults > maxFaults) return false; for (const name of commonProperties) { let ts = smaller.get(name); @@ -70,22 +72,25 @@ function canBeCombined(c1: ClassType, c2: ClassType, onlyWithSameProperties: boo if (ts === undefined || tl === undefined) { return panic(`Both classes should have property ${name}`); } + const tsCases = nonNullTypeCases(ts.type); const tlCases = nonNullTypeCases(tl.type); if (tsCases.size > 0 && tlCases.size > 0 && !typeSetsCanBeCombined(tsCases, tlCases)) { return false; } } + return true; } -function tryAddToClique(c: ClassType, clique: Clique, onlyWithSameProperties: boolean): boolean { +function tryAddToClique (c: ClassType, clique: Clique, onlyWithSameProperties: boolean): boolean { for (const prototype of clique.prototypes) { if (prototype.structurallyCompatible(c)) { clique.members.push(c); return true; } } + for (const prototype of clique.prototypes) { if (canBeCombined(prototype, c, onlyWithSameProperties)) { clique.prototypes.push(c); @@ -93,16 +98,17 @@ function tryAddToClique(c: ClassType, clique: Clique, onlyWithSameProperties: bo return true; } } + return false; } -function findSimilarityCliques( +function findSimilarityCliques ( graph: TypeGraph, onlyWithSameProperties: boolean, - includeFixedClasses: boolean + includeFixedClasses: boolean, ): ClassType[][] { const classCandidates = Array.from(graph.allNamedTypesSeparated().objects).filter( - o => o instanceof ClassType && (includeFixedClasses || !o.isFixed) + o => o instanceof ClassType && (includeFixedClasses || !o.isFixed), ) as ClassType[]; const cliques: Clique[] = []; @@ -114,6 +120,7 @@ function findSimilarityCliques( break; } } + if (cliqueIndex === undefined) { // New clique cliqueIndex = cliques.length; @@ -131,22 +138,22 @@ function findSimilarityCliques( return cliques.map(clique => clique.members).filter(cl => cl.length > 1); } -export function combineClasses( +export function combineClasses ( ctx: RunContext, graph: TypeGraph, alphabetizeProperties: boolean, conflateNumbers: boolean, onlyWithSameProperties: boolean, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { const cliques = ctx.time(" find similarity cliques", () => - findSimilarityCliques(graph, onlyWithSameProperties, false) + findSimilarityCliques(graph, onlyWithSameProperties, false), ); - function makeCliqueClass( + function makeCliqueClass ( clique: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { assert(clique.size > 0, "Clique can't be empty"); const attributes = combineTypeAttributesOfTypes("union", clique); @@ -156,7 +163,7 @@ export function combineClasses( builder, unionBuilderForUnification(builder, false, false, conflateNumbers), conflateNumbers, - forwardingRef + forwardingRef, ); } @@ -166,6 +173,6 @@ export function combineClasses( alphabetizeProperties, cliques, debugPrintReconstitution, - makeCliqueClass + makeCliqueClass, ); } diff --git a/packages/quicktype-core/src/rewrites/ExpandStrings.ts b/packages/quicktype-core/src/rewrites/ExpandStrings.ts index 9cb886d9e..7f2bff226 100644 --- a/packages/quicktype-core/src/rewrites/ExpandStrings.ts +++ b/packages/quicktype-core/src/rewrites/ExpandStrings.ts @@ -6,17 +6,17 @@ import { setUnion, setIntersect, setIsSuperset, - areEqual + areEqual, } from "collection-utils"; -import { PrimitiveType } from "../Type"; +import { type PrimitiveType } from "../Type"; import { stringTypesForType } from "../TypeUtils"; -import { TypeGraph, TypeRef } from "../TypeGraph"; -import { GraphRewriteBuilder } from "../GraphRewriting"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; import { assert, defined } from "../support/Support"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; import { StringTypes } from "../attributes/StringTypes"; -import { RunContext } from "../Run"; +import { type RunContext } from "../Run"; const MIN_LENGTH_FOR_ENUM = 10; @@ -25,36 +25,36 @@ const REQUIRED_OVERLAP = 3 / 4; export type EnumInference = "none" | "all" | "infer"; -type EnumInfo = { +interface EnumInfo { cases: ReadonlySet; numValues: number; -}; +} -function isOwnEnum({ numValues, cases }: EnumInfo): boolean { +function isOwnEnum ({ numValues, cases }: EnumInfo): boolean { return numValues >= MIN_LENGTH_FOR_ENUM && cases.size < Math.sqrt(numValues); } -function enumCasesOverlap( +function enumCasesOverlap ( newCases: ReadonlySet, existingCases: ReadonlySet, - newAreSubordinate: boolean + newAreSubordinate: boolean, ): boolean { const smaller = newAreSubordinate ? newCases.size : Math.min(newCases.size, existingCases.size); const overlap = setIntersect(newCases, existingCases).size; return overlap >= smaller * REQUIRED_OVERLAP; } -function isAlwaysEmptyString(cases: string[]): boolean { +function isAlwaysEmptyString (cases: string[]): boolean { return cases.length === 1 && cases[0] === ""; } -export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: EnumInference): TypeGraph { +export function expandStrings (ctx: RunContext, graph: TypeGraph, inference: EnumInference): TypeGraph { const stringTypeMapping = ctx.stringTypeMapping; const allStrings = Array.from(graph.allTypesUnordered()).filter( - t => t.kind === "string" && stringTypesForType(t as PrimitiveType).isRestricted + t => t.kind === "string" && stringTypesForType(t as PrimitiveType).isRestricted, ) as PrimitiveType[]; - function makeEnumInfo(t: PrimitiveType): EnumInfo | undefined { + function makeEnumInfo (t: PrimitiveType): EnumInfo | undefined { const stringTypes = stringTypesForType(t); const mappedStringTypes = stringTypes.applyStringTypeMapping(stringTypeMapping); if (!mappedStringTypes.isRestricted) return undefined; @@ -76,7 +76,7 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum } const enumInfos = new Map(); - const enumSets: ReadonlySet[] = []; + const enumSets: Array> = []; if (inference !== "none") { for (const t of allStrings) { @@ -85,7 +85,7 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum enumInfos.set(t, enumInfo); } - function findOverlap(newCases: ReadonlySet, newAreSubordinate: boolean): number { + function findOverlap (newCases: ReadonlySet, newAreSubordinate: boolean): number { return enumSets.findIndex(s => enumCasesOverlap(newCases, s, newAreSubordinate)); } @@ -117,6 +117,7 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum // Remove the ones we're done with. enumInfos.delete(t); } + if (inference === "all") { assert(enumInfos.size === 0); } @@ -138,10 +139,10 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum } } - function replaceString( + function replaceString ( group: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { assert(group.size === 1); const t = defined(iterableFirst(group)); @@ -166,6 +167,7 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } } + const transformations = mappedStringTypes.transformations; // FIXME: This is probably wrong, or at least overly conservative. This is for the case // where some attributes are identity ones, i.e. where we can't merge the primitive types, @@ -177,6 +179,7 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum const kind = defined(iterableFirst(transformations)); return builder.getPrimitiveType(kind, attributes, forwardingRef); } + types.push(...Array.from(transformations).map(k => builder.getPrimitiveType(k))); assert(types.length > 0, "We got an empty string type"); return builder.getUnionType(attributes, new Set(types), forwardingRef); @@ -188,6 +191,6 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum false, allStrings.map(t => [t]), ctx.debugPrintReconstitution, - replaceString + replaceString, ); } diff --git a/packages/quicktype-core/src/rewrites/FlattenStrings.ts b/packages/quicktype-core/src/rewrites/FlattenStrings.ts index b700073f5..18ce4da1b 100644 --- a/packages/quicktype-core/src/rewrites/FlattenStrings.ts +++ b/packages/quicktype-core/src/rewrites/FlattenStrings.ts @@ -1,32 +1,32 @@ import { iterableFirst } from "collection-utils"; -import { PrimitiveType, UnionType, Type } from "../Type"; +import { type PrimitiveType, type UnionType, type Type } from "../Type"; import { stringTypesForType, combineTypeAttributesOfTypes } from "../TypeUtils"; -import { TypeGraph, TypeRef } from "../TypeGraph"; -import { StringTypeMapping } from "../TypeBuilder"; -import { GraphRewriteBuilder } from "../GraphRewriting"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; import { assert, defined } from "../support/Support"; import { combineTypeAttributes } from "../attributes/TypeAttributes"; // A union needs replacing if it contains more than one string type, one of them being // a basic string type. -function unionNeedsReplacing(u: UnionType): ReadonlySet | undefined { +function unionNeedsReplacing (u: UnionType): ReadonlySet | undefined { const stringMembers = u.stringTypeMembers; if (stringMembers.size <= 1) return undefined; const stringType = u.findMember("string"); if (stringType === undefined) return undefined; assert( !stringTypesForType(stringType as PrimitiveType).isRestricted, - "We must only flatten strings if we have no restriced strings" + "We must only flatten strings if we have no restriced strings", ); return stringMembers; } // Replaces all string types in an enum with the basic string type. -function replaceUnion( +function replaceUnion ( group: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { assert(group.size === 1); const u = defined(iterableFirst(group)); @@ -37,21 +37,23 @@ function replaceUnion( if (stringMembers.has(t)) continue; types.push(builder.reconstituteType(t)); } + if (types.length === 0) { return builder.getStringType( combineTypeAttributes("union", stringAttributes, u.getAttributes()), undefined, - forwardingRef + forwardingRef, ); } + types.push(builder.getStringType(stringAttributes, undefined)); return builder.getUnionType(u.getAttributes(), new Set(types), forwardingRef); } -export function flattenStrings( +export function flattenStrings ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { const allUnions = graph.allNamedTypesSeparated().unions; const unionsToReplace = Array.from(allUnions) @@ -63,6 +65,6 @@ export function flattenStrings( false, unionsToReplace, debugPrintReconstitution, - replaceUnion + replaceUnion, ); } diff --git a/packages/quicktype-core/src/rewrites/FlattenUnions.ts b/packages/quicktype-core/src/rewrites/FlattenUnions.ts index a88dca2e8..b9ef1d41e 100644 --- a/packages/quicktype-core/src/rewrites/FlattenUnions.ts +++ b/packages/quicktype-core/src/rewrites/FlattenUnions.ts @@ -1,31 +1,34 @@ import { setFilter, iterableSome } from "collection-utils"; -import { TypeGraph, TypeRef, derefTypeRef } from "../TypeGraph"; -import { Type, UnionType, IntersectionType } from "../Type"; +import { type TypeGraph, type TypeRef} from "../TypeGraph"; +import { derefTypeRef } from "../TypeGraph"; +import { type Type} from "../Type"; +import { UnionType, IntersectionType } from "../Type"; import { makeGroupsToFlatten } from "../TypeUtils"; import { assert } from "../support/Support"; -import { StringTypeMapping } from "../TypeBuilder"; -import { GraphRewriteBuilder } from "../GraphRewriting"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; import { unifyTypes, UnifyUnionBuilder } from "../UnifyClasses"; import { messageAssert } from "../Messages"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; -export function flattenUnions( +export function flattenUnions ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, conflateNumbers: boolean, makeObjectTypes: boolean, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): [TypeGraph, boolean] { let needsRepeat = false; - function replace(types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { + function replace (types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { const unionBuilder = new UnifyUnionBuilder(builder, makeObjectTypes, true, trefs => { assert(trefs.length > 0, "Must have at least one type to build union"); trefs = trefs.map(tref => builder.reconstituteType(derefTypeRef(tref, graph))); if (trefs.length === 1) { return trefs[0]; } + needsRepeat = true; return builder.getUnionType(emptyTypeAttributes, new Set(trefs)); }); diff --git a/packages/quicktype-core/src/rewrites/InferMaps.ts b/packages/quicktype-core/src/rewrites/InferMaps.ts index 9190b043b..0092d1dbf 100644 --- a/packages/quicktype-core/src/rewrites/InferMaps.ts +++ b/packages/quicktype-core/src/rewrites/InferMaps.ts @@ -1,27 +1,30 @@ import { iterableFirst, iterableEvery, setMap } from "collection-utils"; -import { Type, ClassType, setOperationCasesEqual, ClassProperty, isPrimitiveStringTypeKind } from "../Type"; +import { type Type, type ClassProperty} from "../Type"; +import { ClassType, setOperationCasesEqual, isPrimitiveStringTypeKind } from "../Type"; import { removeNullFromType } from "../TypeUtils"; import { defined, panic } from "../support/Support"; -import { TypeGraph, TypeRef } from "../TypeGraph"; -import { StringTypeMapping } from "../TypeBuilder"; -import { GraphRewriteBuilder } from "../GraphRewriting"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; import { unifyTypes, unionBuilderForUnification } from "../UnifyClasses"; -import { MarkovChain, load, evaluate } from "../MarkovChain"; +import { type MarkovChain} from "../MarkovChain"; +import { load, evaluate } from "../MarkovChain"; const mapSizeThreshold = 20; const stringMapSizeThreshold = 50; let markovChain: MarkovChain | undefined = undefined; -function nameProbability(name: string): number { +function nameProbability (name: string): number { if (markovChain === undefined) { markovChain = load(); } + return evaluate(markovChain, name); } -function shouldBeMap(properties: ReadonlyMap): ReadonlySet | undefined { +function shouldBeMap (properties: ReadonlyMap): ReadonlySet | undefined { // Only classes with a certain number of properties are inferred // as maps. const numProperties = properties.size; @@ -94,24 +97,27 @@ function shouldBeMap(properties: ReadonlyMap): ReadonlySe firstNonNullCases = nn; } } + allCases.add(p.type); } + if (!canBeMap) { return undefined; } + return allCases; } -export function inferMaps( +export function inferMaps ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, conflateNumbers: boolean, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { - function replaceClass( + function replaceClass ( setOfOneClass: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { const c = defined(iterableFirst(setOfOneClass)); const properties = c.getProperties(); @@ -134,9 +140,9 @@ export function inferMaps( c.getAttributes(), builder, unionBuilderForUnification(builder, false, false, conflateNumbers), - conflateNumbers + conflateNumbers, ), - forwardingRef + forwardingRef, ); } @@ -150,6 +156,6 @@ export function inferMaps( false, classesToReplace.map(c => [c]), debugPrintReconstitution, - replaceClass + replaceClass, ); } diff --git a/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts b/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts index a9245fe38..e225c3c42 100644 --- a/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts +++ b/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts @@ -1,40 +1,40 @@ import { setFilter, iterableFirst, mapMap, setMap } from "collection-utils"; -import { TypeGraph, TypeRef } from "../TypeGraph"; -import { StringTypeMapping } from "../TypeBuilder"; -import { GraphRewriteBuilder } from "../GraphRewriting"; -import { ObjectType, ClassProperty } from "../Type"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; +import { type ObjectType, type ClassProperty } from "../Type"; import { defined } from "../support/Support"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; -export function replaceObjectType( +export function replaceObjectType ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, _conflateNumbers: boolean, leaveFullObjects: boolean, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { - function replace( + function replace ( setOfOneType: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { const o = defined(iterableFirst(setOfOneType)); const attributes = o.getAttributes(); const properties = o.getProperties(); const additionalProperties = o.getAdditionalProperties(); - function reconstituteProperties(): ReadonlyMap { + function reconstituteProperties (): ReadonlyMap { return mapMap(properties, cp => - builder.makeClassProperty(builder.reconstituteTypeRef(cp.typeRef), cp.isOptional) + builder.makeClassProperty(builder.reconstituteTypeRef(cp.typeRef), cp.isOptional), ); } - function makeClass(): TypeRef { + function makeClass (): TypeRef { return builder.getUniqueClassType(attributes, true, reconstituteProperties(), forwardingRef); } - function reconstituteAdditionalProperties(): TypeRef { + function reconstituteAdditionalProperties (): TypeRef { return builder.reconstituteType(defined(additionalProperties)); } diff --git a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts index c68159828..22f2984cb 100644 --- a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts +++ b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts @@ -9,56 +9,60 @@ import { setMap, iterableFind, setIntersect, - setUnionInto + setUnionInto, } from "collection-utils"; -import { TypeGraph, TypeRef } from "../TypeGraph"; -import { StringTypeMapping, TypeBuilder } from "../TypeBuilder"; -import { GraphRewriteBuilder, TypeLookerUp } from "../GraphRewriting"; -import { UnionTypeProvider, UnionBuilder, TypeAttributeMap } from "../UnionBuilder"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { type StringTypeMapping, type TypeBuilder } from "../TypeBuilder"; +import { type GraphRewriteBuilder, type TypeLookerUp } from "../GraphRewriting"; +import { type UnionTypeProvider, type TypeAttributeMap } from "../UnionBuilder"; +import { UnionBuilder } from "../UnionBuilder"; +import { + type Type, + type PrimitiveTypeKind, + type TypeKind} from "../Type"; import { IntersectionType, - Type, UnionType, - PrimitiveTypeKind, ArrayType, isPrimitiveTypeKind, isNumberTypeKind, GenericClassProperty, - TypeKind, - ObjectType + ObjectType, } from "../Type"; import { setOperationMembersRecursively, matchTypeExhaustive, makeGroupsToFlatten } from "../TypeUtils"; import { assert, defined, panic, mustNotHappen } from "../support/Support"; +import { + type TypeAttributes} from "../attributes/TypeAttributes"; import { combineTypeAttributes, - TypeAttributes, emptyTypeAttributes, - makeTypeAttributesInferred + makeTypeAttributesInferred, } from "../attributes/TypeAttributes"; -function canResolve(t: IntersectionType): boolean { +function canResolve (t: IntersectionType): boolean { const members = setOperationMembersRecursively(t, undefined)[0]; if (members.size <= 1) return true; return iterableEvery(members, m => !(m instanceof UnionType) || m.isCanonical); } -function attributesForTypes(types: ReadonlySet): TypeAttributeMap { +function attributesForTypes (types: ReadonlySet): TypeAttributeMap { return mapMapEntries(types.entries(), t => [t.kind, t.getAttributes()] as [T, TypeAttributes]); } type PropertyMap = Map>>; class IntersectionAccumulator - implements UnionTypeProvider, [PropertyMap, ReadonlySet | undefined] | undefined> -{ +implements UnionTypeProvider, [PropertyMap, ReadonlySet | undefined] | undefined> { private _primitiveTypes: Set | undefined; + private readonly _primitiveAttributes: TypeAttributeMap = new Map(); // * undefined: We haven't seen any types yet. // * Set: All types we've seen can be arrays. // * false: At least one of the types seen can't be an array. private _arrayItemTypes: Set | undefined | false; + private _arrayAttributes: TypeAttributes = emptyTypeAttributes; // We start out with all object types allowed, which means @@ -70,12 +74,14 @@ class IntersectionAccumulator // undefined, no object types are allowed, in which case // _additionalPropertyTypes must also be undefined; private _objectProperties: PropertyMap | undefined = new Map(); + private _objectAttributes: TypeAttributes = emptyTypeAttributes; + private _additionalPropertyTypes: Set | undefined = new Set(); private _lostTypeAttributes = false; - private updatePrimitiveTypes(members: Iterable): void { + private updatePrimitiveTypes (members: Iterable): void { const types = setFilter(members, t => isPrimitiveTypeKind(t.kind)); const attributes = attributesForTypes(types); mapMergeWithInto(this._primitiveAttributes, (a, b) => combineTypeAttributes("intersect", a, b), attributes); @@ -97,7 +103,7 @@ class IntersectionAccumulator } } - private updateArrayItemTypes(members: Iterable): void { + private updateArrayItemTypes (members: Iterable): void { const maybeArray = iterableFind(members, t => t instanceof ArrayType) as ArrayType | undefined; if (maybeArray === undefined) { this._arrayItemTypes = false; @@ -113,7 +119,7 @@ class IntersectionAccumulator } } - private updateObjectProperties(members: Iterable): void { + private updateObjectProperties (members: Iterable): void { const maybeObject = iterableFind(members, t => t instanceof ObjectType) as ObjectType | undefined; if (maybeObject === undefined) { this._objectProperties = undefined; @@ -124,7 +130,7 @@ class IntersectionAccumulator this._objectAttributes = combineTypeAttributes( "intersect", this._objectAttributes, - maybeObject.getAttributes() + maybeObject.getAttributes(), ); const objectAdditionalProperties = maybeObject.getAdditionalProperties(); @@ -135,7 +141,7 @@ class IntersectionAccumulator const allPropertyNames = setUnionInto( new Set(this._objectProperties.keys()), - maybeObject.getProperties().keys() + maybeObject.getProperties().keys(), ); for (const name of allPropertyNames) { const existing = defined(this._objectProperties).get(name); @@ -144,13 +150,13 @@ class IntersectionAccumulator if (existing !== undefined && newProperty !== undefined) { const cp = new GenericClassProperty( existing.typeData.add(newProperty.type), - existing.isOptional && newProperty.isOptional + existing.isOptional && newProperty.isOptional, ); defined(this._objectProperties).set(name, cp); } else if (existing !== undefined && objectAdditionalProperties !== undefined) { const cp = new GenericClassProperty( existing.typeData.add(objectAdditionalProperties), - existing.isOptional + existing.isOptional, ); defined(this._objectProperties).set(name, cp); } else if (existing !== undefined) { @@ -174,13 +180,13 @@ class IntersectionAccumulator } } - private addUnionSet(members: Iterable): void { + private addUnionSet (members: Iterable): void { this.updatePrimitiveTypes(members); this.updateArrayItemTypes(members); this.updateObjectProperties(members); } - addType(t: Type): TypeAttributes { + addType (t: Type): TypeAttributes { let attributes = t.getAttributes(); matchTypeExhaustive( t, @@ -203,23 +209,24 @@ class IntersectionAccumulator unionType => { attributes = combineTypeAttributes( "intersect", - [attributes].concat(Array.from(unionType.members).map(m => m.getAttributes())) + [attributes].concat(Array.from(unionType.members).map(m => m.getAttributes())), ); this.addUnionSet(unionType.members); }, - transformedStringType => this.addUnionSet([transformedStringType]) + transformedStringType => this.addUnionSet([transformedStringType]), ); return makeTypeAttributesInferred(attributes); } - get arrayData(): ReadonlySet { + get arrayData (): ReadonlySet { if (this._arrayItemTypes === undefined || this._arrayItemTypes === false) { return panic("This should not be called if the type can't be an array"); } + return this._arrayItemTypes; } - get objectData(): [PropertyMap, ReadonlySet | undefined] | undefined { + get objectData (): [PropertyMap, ReadonlySet | undefined] | undefined { if (this._objectProperties === undefined) { assert(this._additionalPropertyTypes === undefined); return undefined; @@ -228,13 +235,13 @@ class IntersectionAccumulator return [this._objectProperties, this._additionalPropertyTypes]; } - get enumCases(): ReadonlySet { + get enumCases (): ReadonlySet { return panic("We don't support enums in intersections"); } - getMemberKinds(): TypeAttributeMap { + getMemberKinds (): TypeAttributeMap { const kinds: TypeAttributeMap = mapMap(defined(this._primitiveTypes).entries(), k => - defined(this._primitiveAttributes.get(k)) + defined(this._primitiveAttributes.get(k)), ); const maybeDoubleAttributes = this._primitiveAttributes.get("double"); // If double was eliminated, add its attributes to integer @@ -260,19 +267,19 @@ class IntersectionAccumulator return kinds; } - get lostTypeAttributes(): boolean { + get lostTypeAttributes (): boolean { return this._lostTypeAttributes; } } class IntersectionUnionBuilder extends UnionBuilder< - TypeBuilder & TypeLookerUp, - ReadonlySet, - [PropertyMap, ReadonlySet | undefined] | undefined +TypeBuilder & TypeLookerUp, +ReadonlySet, +[PropertyMap, ReadonlySet | undefined] | undefined > { private _createdNewIntersections = false; - private makeIntersection(members: ReadonlySet, attributes: TypeAttributes): TypeRef { + private makeIntersection (members: ReadonlySet, attributes: TypeAttributes): TypeRef { const reconstitutedMembers = setMap(members, t => this.typeBuilder.reconstituteTypeRef(t.typeRef)); const first = defined(iterableFirst(reconstitutedMembers)); @@ -285,14 +292,14 @@ class IntersectionUnionBuilder extends UnionBuilder< return this.typeBuilder.getUniqueIntersectionType(attributes, reconstitutedMembers); } - get createdNewIntersections(): boolean { + get createdNewIntersections (): boolean { return this._createdNewIntersections; } - protected makeObject( + protected makeObject ( maybeData: [PropertyMap, ReadonlySet | undefined] | undefined, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { if (maybeData === undefined) { return panic("Either properties or additional properties must be given to make an object type"); @@ -300,7 +307,7 @@ class IntersectionUnionBuilder extends UnionBuilder< const [propertyTypes, maybeAdditionalProperties] = maybeData; const properties = mapMap(propertyTypes, cp => - this.typeBuilder.makeClassProperty(this.makeIntersection(cp.typeData, emptyTypeAttributes), cp.isOptional) + this.typeBuilder.makeClassProperty(this.makeIntersection(cp.typeData, emptyTypeAttributes), cp.isOptional), ); const additionalProperties = maybeAdditionalProperties === undefined @@ -309,10 +316,10 @@ class IntersectionUnionBuilder extends UnionBuilder< return this.typeBuilder.getUniqueObjectType(typeAttributes, properties, additionalProperties, forwardingRef); } - protected makeArray( + protected makeArray ( arrays: ReadonlySet, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { // FIXME: attributes const itemsType = this.makeIntersection(arrays, emptyTypeAttributes); @@ -321,23 +328,24 @@ class IntersectionUnionBuilder extends UnionBuilder< } } -export function resolveIntersections( +export function resolveIntersections ( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): [TypeGraph, boolean] { let needsRepeat = false; - function replace(types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { + function replace (types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { const intersections = setFilter(types, t => t instanceof IntersectionType) as Set; const [members, intersectionAttributes] = setOperationMembersRecursively( Array.from(intersections), - "intersect" + "intersect", ); if (members.size === 0) { const t = builder.getPrimitiveType("any", intersectionAttributes, forwardingRef); return t; } + if (members.size === 1) { return builder.reconstituteType(defined(iterableFirst(members)), intersectionAttributes, forwardingRef); } @@ -346,8 +354,8 @@ export function resolveIntersections( const extraAttributes = makeTypeAttributesInferred( combineTypeAttributes( "intersect", - Array.from(members).map(t => accumulator.addType(t)) - ) + Array.from(members).map(t => accumulator.addType(t)), + ), ); const attributes = combineTypeAttributes("intersect", intersectionAttributes, extraAttributes); @@ -356,13 +364,15 @@ export function resolveIntersections( if (unionBuilder.createdNewIntersections) { needsRepeat = true; } + return tref; } + // FIXME: We need to handle intersections that resolve to the same set of types. // See for example the intersections-nested.schema example. const allIntersections = setFilter( graph.allTypesUnordered(), - t => t instanceof IntersectionType + t => t instanceof IntersectionType, ) as Set; const resolvableIntersections = setFilter(allIntersections, canResolve); const groups = makeGroupsToFlatten(resolvableIntersections, undefined); diff --git a/packages/quicktype-core/src/support/Acronyms.ts b/packages/quicktype-core/src/support/Acronyms.ts index 21460b0cf..24a40dec1 100644 --- a/packages/quicktype-core/src/support/Acronyms.ts +++ b/packages/quicktype-core/src/support/Acronyms.ts @@ -1096,14 +1096,14 @@ export const acronyms: string[] = [ "zma", "zoi", "zope", - "zpl" + "zpl", ]; export enum AcronymStyleOptions { - Pascal = "pascal", Camel = "camel", + Lower = "lowerCase", Original = "original", - Lower = "lowerCase" + Pascal = "pascal" } export const acronymOption = function (defaultOption: AcronymStyleOptions) { @@ -1114,19 +1114,19 @@ export const acronymOption = function (defaultOption: AcronymStyleOptions) { [AcronymStyleOptions.Original, AcronymStyleOptions.Original], [AcronymStyleOptions.Pascal, AcronymStyleOptions.Pascal], [AcronymStyleOptions.Camel, AcronymStyleOptions.Camel], - [AcronymStyleOptions.Lower, AcronymStyleOptions.Lower] + [AcronymStyleOptions.Lower, AcronymStyleOptions.Lower], ], defaultOption, - "secondary" + "secondary", ); }; -export function acronymStyle(style: AcronymStyleOptions): (s: string) => string { - const options: { [key: string]: (s: string) => string } = { +export function acronymStyle (style: AcronymStyleOptions): (s: string) => string { + const options: { [key: string]: (s: string) => string, } = { [AcronymStyleOptions.Pascal]: allUpperWordStyle, [AcronymStyleOptions.Camel]: firstUpperWordStyle, [AcronymStyleOptions.Original]: originalWord, - [AcronymStyleOptions.Lower]: allLowerWordStyle + [AcronymStyleOptions.Lower]: allLowerWordStyle, }; return options[style]; diff --git a/packages/quicktype-core/src/support/Chance.ts b/packages/quicktype-core/src/support/Chance.ts index 5a368d7e8..72b58a0fb 100644 --- a/packages/quicktype-core/src/support/Chance.ts +++ b/packages/quicktype-core/src/support/Chance.ts @@ -34,20 +34,26 @@ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ class MersenneTwister { - private N: number; - private M: number; - private MATRIX_A: number; - private UPPER_MASK: number; - private LOWER_MASK: number; + private readonly N: number; + + private readonly M: number; + + private readonly MATRIX_A: number; + + private readonly UPPER_MASK: number; + + private readonly LOWER_MASK: number; private mt: number[]; + private mti: number; - constructor(seed: number) { + constructor (seed: number) { if (seed === undefined) { // kept random number same size as time used previously to ensure no unexpected results downstream seed = Math.floor(Math.random() * Math.pow(10, 13)); } + /* Period parameters */ this.N = 624; this.M = 397; @@ -62,12 +68,12 @@ class MersenneTwister { } /* initializes mt[N] with a seed */ - private init_genrand(s: number) { + private init_genrand (s: number) { this.mt[0] = s >>> 0; for (this.mti = 1; this.mti < this.N; this.mti++) { - s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30); + s = this.mt[this.mti - 1] ^ this.mt[this.mti - 1] >>> 30; this.mt[this.mti] = - ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + this.mti; + (((s & 0xffff0000) >>> 16) * 1812433253 << 16) + (s & 0x0000ffff) * 1812433253 + this.mti; /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ @@ -78,9 +84,9 @@ class MersenneTwister { } /* generates a random number on [0,0xffffffff]-interval */ - private genrand_int32() { + private genrand_int32 () { let y; - let mag01 = new Array(0x0, this.MATRIX_A); + let mag01 = [0x0, this.MATRIX_A]; /* mag01[x] = x * MATRIX_A for x=0,1 */ if (this.mti >= this.N) { @@ -91,16 +97,19 @@ class MersenneTwister { /* if init_genrand() has not been called, */ this.init_genrand(5489); /* a default initial seed is used */ } + for (kk = 0; kk < this.N - this.M; kk++) { - y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK); - this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1]; + y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK; + this.mt[kk] = this.mt[kk + this.M] ^ y >>> 1 ^ mag01[y & 0x1]; } + for (; kk < this.N - 1; kk++) { - y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK); - this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1]; + y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK; + this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ y >>> 1 ^ mag01[y & 0x1]; } - y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK); - this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; + + y = this.mt[this.N - 1] & this.UPPER_MASK | this.mt[0] & this.LOWER_MASK; + this.mt[this.N - 1] = this.mt[this.M - 1] ^ y >>> 1 ^ mag01[y & 0x1]; this.mti = 0; } @@ -109,15 +118,15 @@ class MersenneTwister { /* Tempering */ y ^= y >>> 11; - y ^= (y << 7) & 0x9d2c5680; - y ^= (y << 15) & 0xefc60000; + y ^= y << 7 & 0x9d2c5680; + y ^= y << 15 & 0xefc60000; y ^= y >>> 18; return y >>> 0; } /* generates a random number on [0,1)-real-interval */ - random() { + random () { return this.genrand_int32() * (1.0 / 4294967296.0); /* divided by 2^32 */ } @@ -125,14 +134,14 @@ class MersenneTwister { // https://github.com/chancejs/chancejs export class Chance { - private mt: MersenneTwister; + private readonly mt: MersenneTwister; - constructor(readonly seed: number) { + constructor (readonly seed: number) { // If no generator function was provided, use our MT this.mt = new MersenneTwister(this.seed); } - random(): number { + random (): number { return this.mt.random(); } @@ -147,7 +156,7 @@ export class Chance { * @returns {Number} a single random integer number * @throws {RangeError} min cannot be greater than max */ - integer(options: { min: number; max: number }): number { + integer (options: { max: number, min: number, }): number { return Math.floor(this.random() * (options.max - options.min + 1) + options.min); } @@ -162,7 +171,7 @@ export class Chance { * @returns {Number} a single random integer number * @throws {RangeError} min cannot be greater than max */ - natural(options: { max: number }): number { + natural (options: { max: number, }): number { return this.integer({ min: 0, max: options.max }); } @@ -170,21 +179,22 @@ export class Chance { if (arr.length === 0) { throw new RangeError("Chance: Cannot pick() from an empty array"); } + return arr[this.natural({ max: arr.length - 1 })]; } - animal(): string { + animal (): string { // if user does not put in any animal type, will return a random animal regardless const animalTypeArray = ["desert", "forest", "ocean", "zoo", "farm", "pet", "grassland"]; return this.pick(animals[this.pick(animalTypeArray)]); } - city(): string { + city (): string { return this.pick(cities); } } -const animals: { [kind: string]: string[] } = { +const animals: { [kind: string]: string[], } = { // list of ocean animals comes from https://owlcation.com/stem/list-of-ocean-animals ocean: [ "Acantharea", @@ -479,7 +489,7 @@ const animals: { [kind: string]: string[] } = { "Yellow Tube Sponge", "Yellowfin Tuna", "Zebrashark", - "Zooplankton" + "Zooplankton", ], // list of desert, grassland, and forest animals comes from http://www.skyenimals.com/ desert: [ @@ -572,7 +582,7 @@ const animals: { [kind: string]: string[] } = { "Vulture", "Waxwing", "Xerus", - "Zebra" + "Zebra", ], grassland: [ "Aardvark", @@ -715,7 +725,7 @@ const animals: { [kind: string]: string[] } = { "Thornbill", "Thrush", "Toad", - "Tortoise" + "Tortoise", ], forest: [ "Agouti", @@ -911,7 +921,7 @@ const animals: { [kind: string]: string[] } = { "Wolf", "Wombat", "Woodchuck", - "Woodpecker" + "Woodpecker", ], // list of farm animals comes from https://www.buzzle.com/articles/farm-animals-list.html farm: [ @@ -942,7 +952,7 @@ const animals: { [kind: string]: string[] } = { "Silkworm", "Turkey", "Yak", - "Zebu" + "Zebu", ], // list of pet animals comes from https://www.dogbreedinfo.com/pets/pet.htm pet: [ @@ -988,7 +998,7 @@ const animals: { [kind: string]: string[] } = { "Sugar Gliders", "Tarantula", "Turkeys", - "Turtles" + "Turtles", ], // list of zoo animals comes from https://bronxzoo.com/animals zoo: [ @@ -1058,8 +1068,8 @@ const animals: { [kind: string]: string[] } = { "Tufted Puffin", "White Cheeked Gibbon", "White-throated Bee Eater", - "Zebra" - ] + "Zebra", + ], }; // Source: https://en.wikipedia.org/wiki/List_of_population_centers_by_latitude @@ -2160,5 +2170,5 @@ const cities: string[] = [ "Villa Las Estrellas", "Esperanza", "Rothera", - "Concordia" + "Concordia", ]; diff --git a/packages/quicktype-core/src/support/Comments.ts b/packages/quicktype-core/src/support/Comments.ts index 3599cf133..d7d8a5194 100644 --- a/packages/quicktype-core/src/support/Comments.ts +++ b/packages/quicktype-core/src/support/Comments.ts @@ -1,17 +1,21 @@ -import { Sourcelike } from "../Source"; +import { type Sourcelike } from "../Source"; -export type CommentOptions = { - lineStart?: string; - lineEnd?: string; - beforeComment?: string; +export interface CommentOptions { afterComment?: string; + beforeComment?: string; firstLineStart?: string; -}; + lineEnd?: string; + lineStart?: string; +} -type DescriptionBlockCommentConfig = { descriptionBlock: Sourcelike[] }; -type InlineCommentConfig = { lines: Sourcelike[] }; +interface DescriptionBlockCommentConfig { + descriptionBlock: Sourcelike[]; +} +interface InlineCommentConfig { + lines: Sourcelike[]; +} type CustomCommentConfig = CommentOptions & { - customLines: Sourcelike[]; + customLines: Sourcelike[], }; export type CommentConfig = DescriptionBlockCommentConfig | InlineCommentConfig | CustomCommentConfig; diff --git a/packages/quicktype-core/src/support/Converters.ts b/packages/quicktype-core/src/support/Converters.ts index 4231237d3..a06301747 100644 --- a/packages/quicktype-core/src/support/Converters.ts +++ b/packages/quicktype-core/src/support/Converters.ts @@ -1,19 +1,19 @@ import { EnumOption } from "../RendererOptions"; export enum ConvertersOptions { - TopLevel = "top-level", - AllObjects = "all-objects" + AllObjects = "all-objects", + TopLevel = "top-level" } -export function convertersOption() { +export function convertersOption () { return new EnumOption( "converters", "Which converters to generate (top-level by default)", [ [ConvertersOptions.TopLevel, ConvertersOptions.TopLevel], - [ConvertersOptions.AllObjects, ConvertersOptions.AllObjects] + [ConvertersOptions.AllObjects, ConvertersOptions.AllObjects], ], ConvertersOptions.TopLevel, - "secondary" + "secondary", ); } diff --git a/packages/quicktype-core/src/support/Strings.ts b/packages/quicktype-core/src/support/Strings.ts index 8e2e91969..78e1ad378 100644 --- a/packages/quicktype-core/src/support/Strings.ts +++ b/packages/quicktype-core/src/support/Strings.ts @@ -12,9 +12,9 @@ export type NamingStyle = import unicode from "unicode-properties"; -function computeAsciiMap(mapper: (codePoint: number) => string): { - charStringMap: string[]; - charNoEscapeMap: number[]; +function computeAsciiMap (mapper: (codePoint: number) => string): { + charNoEscapeMap: number[], + charStringMap: string[], } { const charStringMap: string[] = []; const charNoEscapeMap: number[] = []; @@ -25,6 +25,7 @@ function computeAsciiMap(mapper: (codePoint: number) => string): { if (result === String.fromCharCode(i)) { noEscape = 1; } + charStringMap.push(result); charNoEscapeMap.push(noEscape); } @@ -34,21 +35,22 @@ function computeAsciiMap(mapper: (codePoint: number) => string): { type CodePointPredicate = (codePoint: number) => boolean; -function precomputedCodePointPredicate(p: CodePointPredicate): CodePointPredicate { +function precomputedCodePointPredicate (p: CodePointPredicate): CodePointPredicate { const asciiResults: boolean[] = []; for (let cp = 0; cp < 128; cp++) { asciiResults.push(p(cp)); } + return function (cp: number) { return cp < 128 ? asciiResults[cp] : p(cp); }; } // FIXME: This is a copy of code in src/Data/String/Util.js -export function utf16ConcatMap(mapper: (utf16Unit: number) => string): (s: string) => string { +export function utf16ConcatMap (mapper: (utf16Unit: number) => string): (s: string) => string { const { charStringMap, charNoEscapeMap } = computeAsciiMap(mapper); - return function stringConcatMap_inner(s: string): string { + return function stringConcatMap_inner (s: string): string { let cs: string[] | null = null; let start = 0; let i = 0; @@ -67,6 +69,7 @@ export function utf16ConcatMap(mapper: (utf16Unit: number) => string): (s: strin start = i + 1; } + i++; } @@ -78,18 +81,18 @@ export function utf16ConcatMap(mapper: (utf16Unit: number) => string): (s: strin }; } -function isHighSurrogate(cc: number): boolean { +function isHighSurrogate (cc: number): boolean { return cc >= 0xd800 && cc <= 0xdbff; } -function isLowSurrogate(cc: number): boolean { +function isLowSurrogate (cc: number): boolean { return cc >= 0xdc00 && cc <= 0xdfff; } -export function utf32ConcatMap(mapper: (codePoint: number) => string): (s: string) => string { +export function utf32ConcatMap (mapper: (codePoint: number) => string): (s: string) => string { const { charStringMap, charNoEscapeMap } = computeAsciiMap(mapper); - return function stringConcatMap_inner(s: string): string { + return function stringConcatMap_inner (s: string): string { let cs: string[] | null = null; let start = 0; let i = 0; @@ -118,6 +121,7 @@ export function utf32ConcatMap(mapper: (codePoint: number) => string): (s: strin start = i + 1; } + i++; } @@ -129,15 +133,15 @@ export function utf32ConcatMap(mapper: (codePoint: number) => string): (s: strin }; } -export function utf16LegalizeCharacters(isLegal: (utf16Unit: number) => boolean): (s: string) => string { - return utf16ConcatMap(u => (isLegal(u) ? String.fromCharCode(u) : "")); +export function utf16LegalizeCharacters (isLegal: (utf16Unit: number) => boolean): (s: string) => string { + return utf16ConcatMap(u => isLegal(u) ? String.fromCharCode(u) : ""); } -export function legalizeCharacters(isLegal: (codePoint: number) => boolean): (s: string) => string { - return utf32ConcatMap(u => (u <= 0xffff && isLegal(u) ? String.fromCharCode(u) : "")); +export function legalizeCharacters (isLegal: (codePoint: number) => boolean): (s: string) => string { + return utf32ConcatMap(u => u <= 0xffff && isLegal(u) ? String.fromCharCode(u) : ""); } -export function repeatString(s: string, n: number): string { +export function repeatString (s: string, n: number): string { assert(n >= 0, "Cannot repeat a string a negative number of times"); if (n === 0) return ""; @@ -149,21 +153,23 @@ export function repeatString(s: string, n: number): string { if (n % 2 !== 0) { result += s; } + n = Math.floor(n / 2); if (n > 0) { s += s; } } while (n > 0); + return result; } -export function intToHex(i: number, width: number): string { +export function intToHex (i: number, width: number): string { let str = i.toString(16); if (str.length >= width) return str; return repeatString("0", width - str.length) + str; } -export function standardUnicodeHexEscape(codePoint: number): string { +export function standardUnicodeHexEscape (codePoint: number): string { if (codePoint <= 0xffff) { return "\\u" + intToHex(codePoint, 4); } else { @@ -171,16 +177,16 @@ export function standardUnicodeHexEscape(codePoint: number): string { } } -export function escapeNonPrintableMapper( +export function escapeNonPrintableMapper ( printablePredicate: (codePoint: number) => boolean, - escaper: (codePoint: number) => string + escaper: (codePoint: number) => string, ): (u: number) => string { - function mapper(u: number): string { + function mapper (u: number): string { switch (u) { case 0x5c: return "\\\\"; case 0x22: - return '\\"'; + return "\\\""; case 0x0a: return "\\n"; case 0x09: @@ -189,16 +195,18 @@ export function escapeNonPrintableMapper( if (printablePredicate(u)) { return String.fromCharCode(u); } + return escaper(u); } } + return mapper; } export const utf16StringEscape = utf16ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape)); export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape)); -export function isPrintable(codePoint: number): boolean { +export function isPrintable (codePoint: number): boolean { if (codePoint > 0xffff) return false; const category = unicode.getCategory(codePoint); return ( @@ -225,91 +233,92 @@ export function isPrintable(codePoint: number): boolean { "Pi", "Nl", "Mn", - "Lo" - ].indexOf(category) >= 0 + "Lo", + ].includes(category) ); } -export function isAscii(codePoint: number): boolean { +export function isAscii (codePoint: number): boolean { return codePoint < 128; } -export function isLetter(codePoint: number): boolean { +export function isLetter (codePoint: number): boolean { const category = unicode.getCategory(codePoint); // FIXME: Include Letter, modifier (Lm)? - return ["Lu", "Ll", "Lt", "Lo"].indexOf(category) >= 0; + return ["Lu", "Ll", "Lt", "Lo"].includes(category); } -export function isDigit(codePoint: number): boolean { +export function isDigit (codePoint: number): boolean { const category = unicode.getCategory(codePoint); - return ["Nd"].indexOf(category) >= 0; + return ["Nd"].includes(category); } -export function isNumeric(codePoint: number): boolean { +export function isNumeric (codePoint: number): boolean { const category = unicode.getCategory(codePoint); - return ["No", "Nd", "Nl"].indexOf(category) >= 0; + return ["No", "Nd", "Nl"].includes(category); } -export function isLetterOrDigit(codePoint: number): boolean { +export function isLetterOrDigit (codePoint: number): boolean { return isLetter(codePoint) || isDigit(codePoint); } -export function isLetterOrUnderscore(codePoint: number): boolean { +export function isLetterOrUnderscore (codePoint: number): boolean { return isLetter(codePoint) || codePoint === 0x5f; } -export function isLetterOrUnderscoreOrDigit(codePoint: number): boolean { +export function isLetterOrUnderscoreOrDigit (codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isDigit(codePoint); } -export function isWordCharacter(codePoint: number): boolean { +export function isWordCharacter (codePoint: number): boolean { return isLetter(codePoint) || isDigit(codePoint); } -export function trimEnd(str: string): string { +export function trimEnd (str: string): string { const l = str.length; let firstWS = l; for (let i = l - 1; i >= 0; i--) { if (!unicode.isWhiteSpace(str.charCodeAt(i))) break; firstWS = i; } + if (firstWS === l) return str; return str.slice(0, firstWS); } -function modifyFirstChar(f: (c: string) => string, s: string): string { +function modifyFirstChar (f: (c: string) => string, s: string): string { if (s === "") return s; return f(s[0]) + s.slice(1); } -export function capitalize(str: string): string { +export function capitalize (str: string): string { return modifyFirstChar(c => c.toUpperCase(), str); } -export function decapitalize(str: string): string { +export function decapitalize (str: string): string { return modifyFirstChar(c => c.toLowerCase(), str); } const wordSeparatorRegex = /[-_. ]+/; -export function pascalCase(str: string): string { +export function pascalCase (str: string): string { const words = str.split(wordSeparatorRegex).map(capitalize); return words.join(""); } -export function camelCase(str: string): string { +export function camelCase (str: string): string { return decapitalize(pascalCase(str)); } -export function snakeCase(str: string): string { +export function snakeCase (str: string): string { const words = splitIntoWords(str).map(({ word }) => word.toLowerCase()); return words.join("_"); } -export function startWithLetter( +export function startWithLetter ( isAllowedStart: (codePoint: number) => boolean, // FIXME: technically, this operates on UTF16 units upper: boolean, - str: string + str: string, ): string { const modify = upper ? capitalize : decapitalize; if (str === "") return modify("empty"); @@ -319,10 +328,10 @@ export function startWithLetter( const knownAcronyms = new Set(acronyms); -export type WordInName = { - word: string; +export interface WordInName { isAcronym: boolean; -}; + word: string; +} const fastIsWordCharacter = precomputedCodePointPredicate(isWordCharacter); const fastIsNonWordCharacter = precomputedCodePointPredicate(cp => !isWordCharacter(cp)); @@ -331,22 +340,23 @@ export const fastIsUpperCase = precomputedCodePointPredicate(cp => unicode.isUpp const fastNonLetter = precomputedCodePointPredicate(cp => !unicode.isLowerCase(cp) && !unicode.isUpperCase(cp)); const fastIsDigit = precomputedCodePointPredicate(isDigit); -export function splitIntoWords(s: string): WordInName[] { +export function splitIntoWords (s: string): WordInName[] { // [start, end, allUpper] - const intervals: [number, number, boolean][] = []; + const intervals: Array<[number, number, boolean]> = []; let intervalStart: number | undefined = undefined; const len = s.length; let i = 0; let lastLowerCaseIndex: number | undefined = undefined; - function atEnd(): boolean { + function atEnd (): boolean { return i >= len; } - function currentCodePoint(): number { + + function currentCodePoint (): number { return defined(s.codePointAt(i)); } - function skipWhile(p: (codePoint: number) => boolean): void { + function skipWhile (p: (codePoint: number) => boolean): void { while (!atEnd()) { const cp = currentCodePoint(); if (!p(cp)) break; @@ -355,31 +365,36 @@ export function splitIntoWords(s: string): WordInName[] { } } - function skipNonWord(): void { + function skipNonWord (): void { skipWhile(fastIsNonWordCharacter); } - function skipLowerCase(): void { + + function skipLowerCase (): void { skipWhile(fastIsLowerCase); } - function skipUpperCase(): void { + + function skipUpperCase (): void { skipWhile(fastIsUpperCase); } - function skipNonLetter(): void { + + function skipNonLetter (): void { skipWhile(fastNonLetter); } - function skipDigits(): void { + + function skipDigits (): void { skipWhile(fastIsDigit); } - function startInterval(): void { + function startInterval (): void { assert(intervalStart === undefined, "Interval started before last one was committed"); intervalStart = i; } - function commitInterval(): void { + function commitInterval (): void { if (intervalStart === undefined) { return panic("Tried to commit interval without starting one"); } + assert(i > intervalStart, "Interval must be non-empty"); // FIXME: This is a hack to avoid splitting up surrogates. We shouldn't // look at surrogates individually in the first place. When we @@ -389,15 +404,17 @@ export function splitIntoWords(s: string): WordInName[] { if (!atEnd() && isLowSurrogate(currentCodePoint())) { i += 1; } + const allUpper = lastLowerCaseIndex === undefined || lastLowerCaseIndex < intervalStart; intervals.push([intervalStart, i, allUpper]); intervalStart = undefined; } - function intervalLength(): number { + function intervalLength (): number { if (intervalStart === undefined) { return panic("Tried to get interval length without starting one"); } + return i - intervalStart; } @@ -425,6 +442,7 @@ export function splitIntoWords(s: string): WordInName[] { if (fastIsWordCharacter(currentCodePoint())) { i -= 1; } + commitInterval(); } } else { @@ -436,39 +454,40 @@ export function splitIntoWords(s: string): WordInName[] { const words: WordInName[] = []; for (const [start, end, allUpper] of intervals) { const word = s.slice(start, end); - const isAcronym = (lastLowerCaseIndex !== undefined && allUpper) || knownAcronyms.has(word.toLowerCase()); + const isAcronym = lastLowerCaseIndex !== undefined && allUpper || knownAcronyms.has(word.toLowerCase()); words.push({ word, isAcronym }); } + return words; } export type WordStyle = (word: string) => string; -export function firstUpperWordStyle(s: string): string { +export function firstUpperWordStyle (s: string): string { assert(s.length > 0, "Cannot style an empty string"); return s[0].toUpperCase() + s.slice(1).toLowerCase(); } -export function allUpperWordStyle(s: string): string { +export function allUpperWordStyle (s: string): string { return s.toUpperCase(); } -export function originalWord(s: string): string { +export function originalWord (s: string): string { return s; } -export function allLowerWordStyle(s: string): string { +export function allLowerWordStyle (s: string): string { return s.toLowerCase(); } -function styleWord(style: WordStyle, word: string): string { +function styleWord (style: WordStyle, word: string): string { assert(word.length > 0, "Tried to style an empty word"); const result = style(word); assert(result.length > 0, "Word style must not make word empty"); return result; } -export function combineWords( +export function combineWords ( words: WordInName[], removeInvalidCharacters: (s: string) => string, firstWordStyle: WordStyle, @@ -476,7 +495,7 @@ export function combineWords( firstWordAcronymStyle: WordStyle, restAcronymStyle: WordStyle, separator: string, - isStartCharacter: (codePoint: number) => boolean + isStartCharacter: (codePoint: number) => boolean, ): string { const legalizedWords: WordInName[] = []; for (const w of words) { @@ -487,7 +506,7 @@ export function combineWords( if (legalizedWords.length === 0) { const validEmpty = removeInvalidCharacters("empty"); - assert(validEmpty.length > 0, 'Word "empty" is invalid in target language'); + assert(validEmpty.length > 0, "Word \"empty\" is invalid in target language"); legalizedWords.push({ word: validEmpty, isAcronym: false }); } @@ -498,11 +517,11 @@ export function combineWords( let restWords: WordInName[]; if (!isStartCharacter(defined(styledFirstWord.codePointAt(0)))) { const validThe = removeInvalidCharacters("the"); - assert(validThe.length > 0, 'Word "the" is invalid in the target language'); + assert(validThe.length > 0, "Word \"the\" is invalid in the target language"); const styledThe = styleWord(firstWordStyle, validThe); assert( isStartCharacter(defined(styledThe.codePointAt(0))), - 'The first character of styling "the" is not a start character' + "The first character of styling \"the\" is not a start character", ); styledWords.push(styledThe); restWords = legalizedWords; @@ -519,15 +538,15 @@ export function combineWords( return styledWords.join(separator); } -export function addPrefixIfNecessary(prefix: string, name: string): string { +export function addPrefixIfNecessary (prefix: string, name: string): string { // Take care not to doubly-prefix type names return name.startsWith(prefix) ? name : prefix + name; } -export function makeNameStyle( +export function makeNameStyle ( namingStyle: NamingStyle, legalizeName: (name: string) => string, - prefix?: string + prefix?: string, ): (rawName: string) => string { let separator: string; let firstWordStyle: WordStyle; @@ -551,6 +570,7 @@ export function makeNameStyle( } else { separator = "_"; } + switch (namingStyle) { case "pascal": case "pascal-upper-acronyms": @@ -581,7 +601,7 @@ export function makeNameStyle( firstWordAcronymStyle, restAcronymStyle, separator, - isLetterOrUnderscore + isLetterOrUnderscore, ); if (prefix !== undefined) { diff --git a/packages/quicktype-core/src/support/Support.ts b/packages/quicktype-core/src/support/Support.ts index 810219df8..ab67bbefc 100644 --- a/packages/quicktype-core/src/support/Support.ts +++ b/packages/quicktype-core/src/support/Support.ts @@ -3,14 +3,17 @@ import * as pako from "pako"; import { messageError } from "../Messages"; import * as YAML from "yaml"; -export type StringMap = { [name: string]: any }; +export interface StringMap { + [name: string]: any; +} -export function isStringMap(x: any): x is StringMap; -export function isStringMap(x: any, checkValue: (v: any) => v is T): x is { [name: string]: T }; -export function isStringMap(x: any, checkValue?: (v: any) => v is T): boolean { +export function isStringMap (x: any): x is StringMap; +export function isStringMap (x: any, checkValue: (v: any) => v is T): x is { [name: string]: T, }; +export function isStringMap (x: any, checkValue?: (v: any) => v is T): boolean { if (typeof x !== "object" || Array.isArray(x) || x === null) { return false; } + if (checkValue !== undefined) { for (const k of Object.getOwnPropertyNames(x)) { const v = x[k]; @@ -19,26 +22,28 @@ export function isStringMap(x: any, checkValue?: (v: any) => v is T): boolean } } } + return true; } -export function checkString(x: any): x is string { +export function checkString (x: any): x is string { return typeof x === "string"; } -export function checkStringMap(x: any): StringMap; -export function checkStringMap(x: any, checkValue: (v: any) => v is T): { [name: string]: T }; -export function checkStringMap(x: any, checkValue?: (v: any) => v is T): StringMap { +export function checkStringMap (x: any): StringMap; +export function checkStringMap (x: any, checkValue: (v: any) => v is T): { [name: string]: T, }; +export function checkStringMap (x: any, checkValue?: (v: any) => v is T): StringMap { if (isStringMap(x, checkValue as any)) return x; return panic(`Value must be an object, but is ${x}`); } -export function checkArray(x: any): any[]; -export function checkArray(x: any, checkItem: (v: any) => v is T): T[]; -export function checkArray(x: any, checkItem?: (v: any) => v is T): T[] { +export function checkArray (x: any): any[]; +export function checkArray (x: any, checkItem: (v: any) => v is T): T[]; +export function checkArray (x: any, checkItem?: (v: any) => v is T): T[] { if (!Array.isArray(x)) { return panic(`Value must be an array, but is ${x}`); } + if (checkItem !== undefined) { for (const v of x) { if (!checkItem(v)) { @@ -46,71 +51,76 @@ export function checkArray(x: any, checkItem?: (v: any) => v is T): T[] { } } } + return x; } -export function defined(x: T | undefined): T { +export function defined (x: T | undefined): T { if (x !== undefined) return x; return panic("Defined value expected, but got undefined"); } -export function nonNull(x: T | null): T { +export function nonNull (x: T | null): T { if (x !== null) return x; return panic("Non-null value expected, but got null"); } -export function assertNever(x: never): never { +export function assertNever (x: never): never { return messageError("InternalError", { message: `Unexpected object ${x as any}` }); } -export function assert(condition: boolean, message = "Assertion failed"): void { +export function assert (condition: boolean, message = "Assertion failed"): void { if (!condition) { return messageError("InternalError", { message }); } } -export function panic(message: string): never { +export function panic (message: string): never { return messageError("InternalError", { message }); } -export function mustNotHappen(): never { +export function mustNotHappen (): never { return panic("This must not happen"); } -export function repeated(n: number, value: T): T[] { +export function repeated (n: number, value: T): T[] { const arr: T[] = []; for (let i = 0; i < n; i++) { arr.push(value); } + return arr; } -export function repeatedCall(n: number, producer: () => T): T[] { +export function repeatedCall (n: number, producer: () => T): T[] { const arr: T[] = []; for (let i = 0; i < n; i++) { arr.push(producer()); } + return arr; } -export function errorMessage(e: any): string { +export function errorMessage (e: any): string { if (e instanceof Error) { return e.message; } + return e.toString(); } -export function inflateBase64(encoded: string): string { +export function inflateBase64 (encoded: string): string { const bytes = Base64.atob(encoded); return pako.inflate(bytes, { to: "string" }); } -export function parseJSON(text: string, description: string, address = ""): any { +export function parseJSON (text: string, description: string, address = ""): any { try { // https://gist.github.com/pbakondy/f5045eff725193dad9c7 if (text.charCodeAt(0) === 0xfeff) { text = text.slice(1); } + return YAML.parse(text); } catch (e) { let message: string; @@ -125,11 +135,11 @@ export function parseJSON(text: string, description: string, address = " nn.typeRef).add(builder.getPrimitiveType("null"))); @@ -104,24 +109,26 @@ function makeNullable( // union if the type is modified to be non-nullable. That means that the union // (and the null) might be left unreachable in the graph. Provenance checking // won't work in this case, which is why it's disabled in testing for GraphQL. -function removeNull(builder: TypeBuilder, tref: TypeRef): TypeRef { +function removeNull (builder: TypeBuilder, tref: TypeRef): TypeRef { const t = derefTypeRef(tref, builder.typeGraph); if (!(t instanceof UnionType)) { return tref; } + const nonNulls = removeNullFromUnion(t)[1]; const first = iterableFirst(nonNulls); if (first) { if (nonNulls.size === 1) return first.typeRef; return builder.getUnionType( t.getAttributes(), - setMap(nonNulls, nn => nn.typeRef) + setMap(nonNulls, nn => nn.typeRef), ); } + return panic("Trying to remove null results in empty union."); } -function makeScalar(builder: TypeBuilder, ft: GQLType): TypeRef { +function makeScalar (builder: TypeBuilder, ft: GQLType): TypeRef { switch (ft.name) { case "Boolean": return builder.getPrimitiveType("bool"); @@ -135,40 +142,42 @@ function makeScalar(builder: TypeBuilder, ft: GQLType): TypeRef { } } -function hasOptionalDirectives(directives?: DirectiveNode[]): boolean { +function hasOptionalDirectives (directives?: DirectiveNode[]): boolean { if (!directives) return false; for (const d of directives) { const name = d.name.value; if (name === "include" || name === "skip") return true; } + return false; } interface Selection { - selection: SelectionNode; inType: GQLType; optional: boolean; + selection: SelectionNode; } -function expandSelectionSet(selectionSet: SelectionSetNode, inType: GQLType, optional: boolean): Selection[] { +function expandSelectionSet (selectionSet: SelectionSetNode, inType: GQLType, optional: boolean): Selection[] { return selectionSet.selections .reverse() .map(s => ({ selection: s, inType, optional: optional || hasOptionalDirectives(s.directives) })); } interface GQLSchema { - readonly types: { [name: string]: GQLType }; - readonly queryType: GQLType; readonly mutationType?: GQLType; + readonly queryType: GQLType; + readonly types: { [name: string]: GQLType, }; } class GQLQuery { private readonly _schema: GQLSchema; - private readonly _fragments: { [name: string]: FragmentDefinitionNode }; - readonly queries: ReadonlyArray; + private readonly _fragments: { [name: string]: FragmentDefinitionNode, }; + + readonly queries: readonly OperationDefinitionNode[]; - constructor(schema: GQLSchema, queryString: string) { + constructor (schema: GQLSchema, queryString: string) { this._schema = schema; this._fragments = {}; @@ -183,15 +192,16 @@ class GQLQuery { this._fragments[def.name.value] = def; } } + messageAssert(queries.length >= 1, "GraphQLNoQueriesDefined", {}); this.queries = queries; } - private makeIRTypeFromFieldNode = ( + private readonly makeIRTypeFromFieldNode = ( builder: TypeBuilder, fieldNode: FieldNode, fieldType: GQLType, - containingTypeName: string + containingTypeName: string, ): TypeRef => { let optional = hasOptionalDirectives(fieldNode.directives); let result: TypeRef; @@ -206,6 +216,7 @@ class GQLQuery { if (!fieldNode.selectionSet) { return panic("No selection set on object or interface"); } + return makeNullable( builder, this.makeIRTypeFromSelectionSet( @@ -213,16 +224,17 @@ class GQLQuery { fieldNode.selectionSet, fieldType, fieldNode.name.value, - containingTypeName + containingTypeName, ), fieldNode.name.value, null, - containingTypeName + containingTypeName, ); case TypeKind.ENUM: if (!fieldType.enumValues) { return panic("Enum type doesn't have values"); } + const values = fieldType.enumValues.map(ev => ev.name); let name: string; let fieldName: string | null; @@ -233,6 +245,7 @@ class GQLQuery { name = fieldNode.name.value; fieldName = null; } + optional = true; result = builder.getEnumType(makeNames(name, fieldName, containingTypeName), new Set(values)); break; @@ -243,43 +256,47 @@ class GQLQuery { if (!fieldType.ofType) { return panic("No type for list"); } + optional = true; result = builder.getArrayType( emptyTypeAttributes, - this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName) + this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName), ); break; case TypeKind.NON_NULL: if (!fieldType.ofType) { return panic("No type for non-null"); } + result = removeNull( builder, - this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName) + this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName), ); break; default: return assertNever(fieldType.kind); } + if (optional) { result = makeNullable(builder, result, fieldNode.name.value, null, containingTypeName); } + return result; }; - private getFragment = (name: string): FragmentDefinitionNode => { + private readonly getFragment = (name: string): FragmentDefinitionNode => { const fragment = this._fragments[name]; if (!fragment) return panic(`Fragment ${name} is not defined.`); return fragment; }; - private makeIRTypeFromSelectionSet = ( + private readonly makeIRTypeFromSelectionSet = ( builder: TypeBuilder, selectionSet: SelectionSetNode, gqlType: GQLType, containingFieldName: string | null, containingTypeName: string | null, - overrideName?: string + overrideName?: string, ): TypeRef => { if ( gqlType.kind !== TypeKind.OBJECT && @@ -288,9 +305,11 @@ class GQLQuery { ) { return panic("Type for selection set is not object, interface, or union."); } + if (!gqlType.name) { return panic("Object, interface, or union type doesn't have a name."); } + const nameOrOverride = overrideName || gqlType.name; const properties = new Map(); let selections = expandSelectionSet(selectionSet, gqlType, false); @@ -314,6 +333,7 @@ class GQLQuery { selections = selections.concat(expanded); break; } + case "InlineFragment": { // FIXME: support type conditions with discriminated unions const fragmentType = selection.typeCondition @@ -325,14 +345,16 @@ class GQLQuery { selections = selections.concat(expanded); break; } + default: assertNever(selection); } } + return builder.getClassType(makeNames(nameOrOverride, containingFieldName, containingTypeName), properties); }; - makeType(builder: TypeBuilder, query: OperationDefinitionNode, queryName: string): TypeRef { + makeType (builder: TypeBuilder, query: OperationDefinitionNode, queryName: string): TypeRef { if (query.operation === "query") { return this.makeIRTypeFromSelectionSet( builder, @@ -340,7 +362,7 @@ class GQLQuery { this._schema.queryType, null, queryName, - "data" + "data", ); } @@ -355,7 +377,7 @@ class GQLQuery { this._schema.mutationType, null, queryName, - "data" + "data", ); } @@ -364,13 +386,15 @@ class GQLQuery { } class GQLSchemaFromJSON implements GQLSchema { - readonly types: { [name: string]: GQLType } = {}; - // @ts-ignore: The constructor can return early, but only by throwing. + readonly types: { [name: string]: GQLType, } = {}; + + // @ts-expect-error: The constructor can return early, but only by throwing. readonly queryType: GQLType; - // @ts-ignore: The constructor can return early, but only by throwing. + + // @ts-expect-error: The constructor can return early, but only by throwing. readonly mutationType?: GQLType; - constructor(json: any) { + constructor (json: any) { const schema: GraphQLSchema = json.data; if (schema.__schema.queryType.name === null) { @@ -381,6 +405,7 @@ class GQLSchemaFromJSON implements GQLSchema { if (!t.name) return panic("No top-level type name given"); this.types[t.name] = { kind: t.kind, name: t.name, description: t.description }; } + for (const t of schema.__schema.types) { if (!t.name) return panic("This cannot happen"); const type = this.types[t.name]; @@ -392,6 +417,7 @@ class GQLSchemaFromJSON implements GQLSchema { if (queryType === undefined) { return panic("Query type not found."); } + // console.log(`query type ${queryType.name} is ${queryType.kind}`); this.queryType = queryType; @@ -411,30 +437,34 @@ class GQLSchemaFromJSON implements GQLSchema { this.mutationType = mutationType; } - private addTypeFields = (target: GQLType, source: GQLType): void => { + private readonly addTypeFields = (target: GQLType, source: GQLType): void => { if (source.fields) { target.fields = source.fields.map(f => { return { name: f.name, description: f.description, type: this.makeType(f.type), - args: f.args.map(this.makeInputValue) + args: f.args.map(this.makeInputValue), }; }); // console.log(`${target.name} has ${target.fields.length} fields`); } + if (source.interfaces) { target.interfaces = source.interfaces.map(this.makeType); // console.log(`${target.name} has ${target.interfaces.length} interfaces`); } + if (source.possibleTypes) { target.possibleTypes = source.possibleTypes.map(this.makeType); // console.log(`${target.name} has ${target.possibleTypes.length} possibleTypes`); } + if (source.inputFields) { target.inputFields = source.inputFields.map(this.makeInputValue); // console.log(`${target.name} has ${target.inputFields.length} inputFields`); } + if (source.enumValues) { target.enumValues = source.enumValues.map(ev => { return { name: ev.name, description: ev.description }; @@ -443,37 +473,38 @@ class GQLSchemaFromJSON implements GQLSchema { } }; - private makeInputValue = (iv: InputValue): InputValue => { + private readonly makeInputValue = (iv: InputValue): InputValue => { return { name: iv.name, description: iv.description, type: this.makeType(iv.type), - defaultValue: iv.defaultValue + defaultValue: iv.defaultValue, }; }; - private makeType = (t: GQLType): GQLType => { + private readonly makeType = (t: GQLType): GQLType => { if (t.name) { const namedType = this.types[t.name]; if (!namedType) return panic(`Type ${t.name} not found`); return namedType; } + if (!t.ofType) return panic(`Type of kind ${t.kind} has neither name nor ofType`); const type: GQLType = { kind: t.kind, description: t.description, - ofType: this.makeType(t.ofType) + ofType: this.makeType(t.ofType), }; this.addTypeFields(type, t); return type; }; } -function makeGraphQLQueryTypes( +function makeGraphQLQueryTypes ( topLevelName: string, builder: TypeBuilder, json: any, - queryString: string + queryString: string, ): Map { const schema = new GQLSchemaFromJSON(json); const query = new GQLQuery(schema, queryString); @@ -483,69 +514,77 @@ function makeGraphQLQueryTypes( if (types.has(queryName)) { return panic(`Duplicate query name ${queryName}`); } + const dataType = query.makeType(builder, odn, queryName); const dataOrNullType = builder.getUnionType( emptyTypeAttributes, - new Set([dataType, builder.getPrimitiveType("null")]) + new Set([dataType, builder.getPrimitiveType("null")]), ); const errorType = builder.getClassType( namesTypeAttributeKind.makeAttributes(TypeNames.make(new Set(["error"]), new Set(["graphQLError"]), false)), mapFromObject({ message: builder.makeClassProperty( builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted), - false - ) - }) + false, + ), + }), ); const errorArray = builder.getArrayType( namesTypeAttributeKind.makeAttributes( - TypeNames.make(new Set(["errors"]), new Set(["graphQLErrors"]), false) + TypeNames.make(new Set(["errors"]), new Set(["graphQLErrors"]), false), ), - errorType + errorType, ); const t = builder.getClassType( makeNamesTypeAttributes(queryName, false), mapFromObject({ data: builder.makeClassProperty(dataOrNullType, false), - errors: builder.makeClassProperty(errorArray, true) - }) + errors: builder.makeClassProperty(errorArray, true), + }), ); types.set(queryName, t); } + return types; } -export type GraphQLSourceData = { name: string; schema: any; query: string }; +export interface GraphQLSourceData { + name: string; query: string; schema: any; +} -type GraphQLTopLevel = { schema: any; query: string }; +interface GraphQLTopLevel { + query: string; schema: any; +} export class GraphQLInput implements Input { readonly kind: string = "graphql"; + readonly needIR: boolean = true; + readonly needSchemaProcessing: boolean = false; private readonly _topLevels: Map = new Map(); - async addSource(source: GraphQLSourceData): Promise { + async addSource (source: GraphQLSourceData): Promise { this.addSourceSync(source); } - addSourceSync(source: GraphQLSourceData): void { + addSourceSync (source: GraphQLSourceData): void { this._topLevels.set(source.name, { schema: source.schema, - query: source.query + query: source.query, }); } - singleStringSchemaSource(): undefined { + singleStringSchemaSource (): undefined { return undefined; } - async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise { - return this.addTypesSync(ctx, typeBuilder); + async addTypes (ctx: RunContext, typeBuilder: TypeBuilder): Promise { + this.addTypesSync(ctx, typeBuilder); } - addTypesSync(_ctx: RunContext, typeBuilder: TypeBuilder): void { + addTypesSync (_ctx: RunContext, typeBuilder: TypeBuilder): void { for (const [name, { schema, query }] of this._topLevels) { const newTopLevels = makeGraphQLQueryTypes(name, typeBuilder, schema, query); for (const [actualName, t] of newTopLevels) { diff --git a/packages/quicktype-typescript-input/src/index.ts b/packages/quicktype-typescript-input/src/index.ts index 145cc50e1..47696ce83 100644 --- a/packages/quicktype-typescript-input/src/index.ts +++ b/packages/quicktype-typescript-input/src/index.ts @@ -1,13 +1,15 @@ import * as ts from "typescript"; -import { PartialArgs, generateSchema } from "@mark.probst/typescript-json-schema"; +import { type PartialArgs} from "@mark.probst/typescript-json-schema"; +import { generateSchema } from "@mark.probst/typescript-json-schema"; -import { defined, JSONSchemaSourceData, messageError } from "quicktype-core"; +import { type JSONSchemaSourceData} from "quicktype-core"; +import { defined, messageError } from "quicktype-core"; const settings: PartialArgs = { required: true, titles: true, topRef: true, - noExtraProps: true + noExtraProps: true, }; const compilerOptions: ts.CompilerOptions = { @@ -18,18 +20,18 @@ const compilerOptions: ts.CompilerOptions = { module: ts.ModuleKind.CommonJS, strictNullChecks: true, typeRoots: [], - rootDir: "." + rootDir: ".", }; // FIXME: We're stringifying and then parsing this schema again. Just pass around // the schema directly. -export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchemaSourceData { +export function schemaForTypeScriptSources (sourceFileNames: string[]): JSONSchemaSourceData { const program = ts.createProgram(sourceFileNames, compilerOptions); const diagnostics = ts.getPreEmitDiagnostics(program); const error = diagnostics.find(d => d.category === ts.DiagnosticCategory.Error); if (error !== undefined) { return messageError("TypeScriptCompilerError", { - message: ts.flattenDiagnosticMessageText(error.messageText, "\n") + message: ts.flattenDiagnosticMessageText(error.messageText, "\n"), }); } @@ -49,7 +51,7 @@ export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchem } const description = definition.description as string; - const matches = description.match(/#TopLevel/); + const matches = /#TopLevel/.exec(description); if (matches === null) { continue; } @@ -70,11 +72,14 @@ export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchem } } } + if (uris.length === 0) { uris.push("#/definitions/"); } + if (topLevelName === undefined) { topLevelName = ""; } + return { schema: JSON.stringify(schema), name: topLevelName, uris, isConverted: true }; } diff --git a/src/CompressedJSONFromStream.ts b/src/CompressedJSONFromStream.ts index 84c6ffe6f..850da2fc1 100644 --- a/src/CompressedJSONFromStream.ts +++ b/src/CompressedJSONFromStream.ts @@ -1,8 +1,9 @@ -import { Readable } from "readable-stream"; -import { CompressedJSON, Value } from "quicktype-core"; +import { type Readable } from "readable-stream"; +import { type Value } from "quicktype-core"; +import { CompressedJSON } from "quicktype-core"; import { Parser } from "stream-json"; -const methodMap: { [name: string]: string } = { +const methodMap: { [name: string]: string, } = { startObject: "pushObjectContext", endObject: "finishObject", startArray: "pushArrayContext", @@ -14,13 +15,13 @@ const methodMap: { [name: string]: string } = { stringValue: "commitString", nullValue: "commitNull", trueValue: "handleTrueValue", - falseValue: "handleFalseValue" + falseValue: "handleFalseValue", }; export class CompressedJSONFromStream extends CompressedJSON { - async parse(readStream: Readable): Promise { + async parse (readStream: Readable): Promise { const combo = new Parser({ packKeys: true, packStrings: true }); - combo.on("data", (item: { name: string; value: string | undefined }) => { + combo.on("data", (item: { name: string, value: string | undefined, }) => { if (typeof methodMap[item.name] === "string") { (this as any)[methodMap[item.name]](item.value); } @@ -36,7 +37,7 @@ export class CompressedJSONFromStream extends CompressedJSON { readStream.setEncoding("utf8"); readStream.pipe(combo); readStream.resume(); - return promise; + return await promise; } protected handleStartNumber = (): void => { @@ -51,17 +52,17 @@ export class CompressedJSONFromStream extends CompressedJSON { } }; - protected handleEndNumber(): void { + protected handleEndNumber (): void { const isDouble = this.context.currentNumberIsDouble; this.popContext(); this.commitNumber(isDouble); } - protected handleTrueValue(): void { + protected handleTrueValue (): void { this.commitBoolean(true); } - protected handleFalseValue(): void { + protected handleFalseValue (): void { this.commitBoolean(false); } } diff --git a/src/GraphQLIntrospection.ts b/src/GraphQLIntrospection.ts index 71106b1df..b62122ec5 100644 --- a/src/GraphQLIntrospection.ts +++ b/src/GraphQLIntrospection.ts @@ -5,24 +5,26 @@ import { exceptionToString } from "@glideapps/ts-necessities"; import fetch from "cross-fetch"; // https://github.com/apollographql/apollo-codegen/blob/master/src/downloadSchema.ts -const defaultHeaders: { [name: string]: string } = { +const defaultHeaders: { [name: string]: string, } = { Accept: "application/json", - "Content-Type": "application/json" + "Content-Type": "application/json", }; const headerRegExp = /^([^:]+):\s*(.*)$/; -export async function introspectServer(url: string, method: string, headerStrings: string[]): Promise { - const headers: { [name: string]: string } = {}; +export async function introspectServer (url: string, method: string, headerStrings: string[]): Promise { + const headers: { [name: string]: string, } = {}; for (const name of Object.getOwnPropertyNames(defaultHeaders)) { headers[name] = defaultHeaders[name]; } + for (const str of headerStrings) { - const matches = str.match(headerRegExp); + const matches = headerRegExp.exec(str); if (matches === null) { return panic(`Not a valid HTTP header: "${str}"`); } + headers[matches[1]] = matches[2]; } @@ -31,7 +33,7 @@ export async function introspectServer(url: string, method: string, headerString const response = await fetch(url, { method, headers: headers, - body: JSON.stringify({ query: introspectionQuery }) + body: JSON.stringify({ query: introspectionQuery }), }); result = await response.json(); diff --git a/src/TypeSource.ts b/src/TypeSource.ts index cc693c4c9..ab0580889 100644 --- a/src/TypeSource.ts +++ b/src/TypeSource.ts @@ -1,7 +1,7 @@ -import { Readable } from "readable-stream"; +import { type Readable } from "readable-stream"; -import { JSONSourceData, JSONSchemaSourceData } from "quicktype-core"; -import { GraphQLSourceData } from "quicktype-graphql-input"; +import { type JSONSourceData, type JSONSchemaSourceData } from "quicktype-core"; +import { type GraphQLSourceData } from "quicktype-graphql-input"; export interface JSONTypeSource extends JSONSourceData { kind: "json"; diff --git a/src/URLGrammar.ts b/src/URLGrammar.ts index 5280846f0..25ac55c5c 100644 --- a/src/URLGrammar.ts +++ b/src/URLGrammar.ts @@ -1,9 +1,10 @@ import { panic, checkStringMap, checkArray } from "quicktype-core"; -function expand(json: any): string[] { +function expand (json: any): string[] { if (typeof json === "string") { return [json]; } + if (Array.isArray(json)) { let result: string[] = [""]; for (const j of json) { @@ -14,10 +15,13 @@ function expand(json: any): string[] { appended.push(a + b); } } + result = appended; } + return result; } + if (Object.prototype.hasOwnProperty.call(json, "oneOf")) { const options = checkArray(json.oneOf); const result: string[] = []; @@ -26,14 +30,16 @@ function expand(json: any): string[] { result.push(x); } } + return result; } + return panic(`Value is not a valid URL grammar: ${json}`); } -export function urlsFromURLGrammar(json: any): { [name: string]: string[] } { +export function urlsFromURLGrammar (json: any): { [name: string]: string[], } { const topLevelMap = checkStringMap(json); - const results: { [name: string]: string[] } = {}; + const results: { [name: string]: string[], } = {}; for (const name of Object.getOwnPropertyNames(topLevelMap)) { results[name] = expand(topLevelMap[name]); diff --git a/src/index.ts b/src/index.ts index 109161c79..710b5cc9e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,21 +2,23 @@ import * as fs from "fs"; import * as path from "path"; import * as _ from "lodash"; -import { Readable } from "readable-stream"; +import { type Readable } from "readable-stream"; import { hasOwnProperty, definedMap, withDefault, mapFromObject, mapMap } from "collection-utils"; import { exceptionToString } from "@glideapps/ts-necessities"; import { - Options, - RendererOptions, + type Options, + type RendererOptions, + type SerializedRenderResult, + type TargetLanguage, + type OptionDefinition, + type JSONSourceData} from "quicktype-core"; +import { getTargetLanguage, quicktypeMultiFile, - SerializedRenderResult, - TargetLanguage, languageNamed, InputData, JSONSchemaInput, - OptionDefinition, defaultTargetLanguages, IssueAnnotationData, panic, @@ -32,19 +34,18 @@ import { inferenceFlagNames, splitIntoWords, capitalize, - JSONSourceData, JSONInput, getStream, readableFromFileOrURL, readFromFileOrURL, - FetchingJSONSchemaStore + FetchingJSONSchemaStore, } from "quicktype-core"; import { schemaForTypeScriptSources } from "quicktype-typescript-input"; import { GraphQLInput } from "quicktype-graphql-input"; import { urlsFromURLGrammar } from "./URLGrammar"; import { introspectServer } from "./GraphQLIntrospection"; -import { JSONTypeSource, TypeSource, GraphQLTypeSource, SchemaTypeSource } from "./TypeSource"; +import { type JSONTypeSource, type TypeSource, type GraphQLTypeSource, type SchemaTypeSource } from "./TypeSource"; import { CompressedJSONFromStream } from "./CompressedJSONFromStream"; const stringToStream = require("string-to-stream"); @@ -57,53 +58,53 @@ const wordWrap: (s: string) => string = require("wordwrap")(90); const packageJSON = require("../package.json"); export interface CLIOptions { - lang: string; - topLevel: string; - src: string[]; - srcUrls?: string; - srcLang: string; + // We use this to access the inference flags + [option: string]: any; additionalSchema: string[]; - graphqlSchema?: string; + allPropertiesOptional: boolean; + alphabetizeProperties: boolean; + buildMarkovChain?: string; + debug?: string; graphqlIntrospect?: string; + graphqlSchema?: string; + help: boolean; httpHeader?: string[]; httpMethod?: string; - out?: string; - buildMarkovChain?: string; + lang: string; - alphabetizeProperties: boolean; - allPropertiesOptional: boolean; noRender: boolean; + out?: string; + quiet: boolean; rendererOptions: RendererOptions; - help: boolean; - quiet: boolean; - version: boolean; - debug?: string; + src: string[]; + srcLang: string; + srcUrls?: string; telemetry?: string; + topLevel: string; - // We use this to access the inference flags - [option: string]: any; + version: boolean; } const defaultDefaultTargetLanguageName = "go"; -async function sourceFromFileOrUrlArray( +async function sourceFromFileOrUrlArray ( name: string, filesOrUrls: string[], - httpHeaders?: string[] + httpHeaders?: string[], ): Promise { - const samples = await Promise.all(filesOrUrls.map(file => readableFromFileOrURL(file, httpHeaders))); + const samples = await Promise.all(filesOrUrls.map(async file => await readableFromFileOrURL(file, httpHeaders))); return { kind: "json", name, samples }; } -function typeNameFromFilename(filename: string): string { +function typeNameFromFilename (filename: string): string { const name = path.basename(filename); return name.substring(0, name.lastIndexOf(".")); } -async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Promise { - async function readFilesOrURLsInDirectory(d: string): Promise { +async function samplesFromDirectory (dataDir: string, httpHeaders?: string[]): Promise { + async function readFilesOrURLsInDirectory (d: string): Promise { const files = fs .readdirSync(d) .map(x => path.join(d, x)) @@ -128,17 +129,17 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr sourcesInDir.push({ kind: "json", name, - samples: [await readableFromFileOrURL(fileOrUrl, httpHeaders)] + samples: [await readableFromFileOrURL(fileOrUrl, httpHeaders)], }); } else if (file.endsWith(".schema")) { sourcesInDir.push({ kind: "schema", name, - uris: [fileOrUrl] + uris: [fileOrUrl], }); } else if (file.endsWith(".gqlschema")) { messageAssert(graphQLSchema === undefined, "DriverMoreThanOneGraphQLSchemaInDir", { - dir: dataDir + dir: dataDir, }); graphQLSchema = await readableFromFileOrURL(fileOrUrl, httpHeaders); graphQLSchemaFileName = fileOrUrl; @@ -147,7 +148,7 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr kind: "graphql", name, schema: undefined, - query: await getStream(await readableFromFileOrURL(fileOrUrl, httpHeaders)) + query: await getStream(await readableFromFileOrURL(fileOrUrl, httpHeaders)), }); } } @@ -156,6 +157,7 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr if (graphQLSchema === undefined) { return messageError("DriverNoGraphQLSchemaInDir", { dir: dataDir }); } + const schema = parseJSON(await getStream(graphQLSchema), "GraphQL schema", graphQLSchemaFileName); for (const source of graphQLSources) { source.schema = schema; @@ -205,9 +207,10 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr sources.push({ kind: "json", name: path.basename(dir), - samples: jsonSamples + samples: jsonSamples, }); } + sources = sources.concat(schemaSources); sources = sources.concat(graphQLSources); } @@ -215,20 +218,21 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr return sources; } -function inferLang(options: Partial, defaultLanguage: string): string { +function inferLang (options: Partial, defaultLanguage: string): string { // Output file extension determines the language if language is undefined if (options.out !== undefined) { let extension = path.extname(options.out); if (extension === "") { return messageError("DriverNoLanguageOrExtension", {}); } + return extension.slice(1); } return defaultLanguage; } -function inferTopLevel(options: Partial): string { +function inferTopLevel (options: Partial): string { // Output file name determines the top-level if undefined if (options.out !== undefined) { let extension = path.extname(options.out); @@ -247,7 +251,7 @@ function inferTopLevel(options: Partial): string { return "TopLevel"; } -function inferCLIOptions(opts: Partial, targetLanguage: TargetLanguage | undefined): CLIOptions { +function inferCLIOptions (opts: Partial, targetLanguage: TargetLanguage | undefined): CLIOptions { let srcLang = opts.srcLang; if (opts.graphqlSchema !== undefined || opts.graphqlIntrospect !== undefined) { messageAssert(srcLang === undefined || srcLang === "graphql", "DriverSourceLangMustBeGraphQL", {}); @@ -268,6 +272,7 @@ function inferCLIOptions(opts: Partial, targetLanguage: TargetLangua if (maybeLanguage === undefined) { return messageError("DriverUnknownOutputLanguage", { lang: languageName }); } + language = maybeLanguage; } @@ -292,63 +297,65 @@ function inferCLIOptions(opts: Partial, targetLanguage: TargetLangua httpMethod: opts.httpMethod, httpHeader: opts.httpHeader, debug: opts.debug, - telemetry: opts.telemetry + telemetry: opts.telemetry, }; for (const flagName of inferenceFlagNames) { const cliName = negatedInferenceFlagName(flagName); options[cliName] = !!opts[cliName]; } + return options; } -function makeLangTypeLabel(targetLanguages: TargetLanguage[]): string { +function makeLangTypeLabel (targetLanguages: TargetLanguage[]): string { assert(targetLanguages.length > 0, "Must have at least one target language"); return targetLanguages.map(r => _.minBy(r.names, s => s.length)).join("|"); } -function negatedInferenceFlagName(name: string): string { +function negatedInferenceFlagName (name: string): string { const prefix = "infer"; if (name.startsWith(prefix)) { name = name.slice(prefix.length); } + return "no" + capitalize(name); } -function dashedFromCamelCase(name: string): string { +function dashedFromCamelCase (name: string): string { return splitIntoWords(name) .map(w => w.word.toLowerCase()) .join("-"); } -function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinition[] { +function makeOptionDefinitions (targetLanguages: TargetLanguage[]): OptionDefinition[] { const beforeLang: OptionDefinition[] = [ { name: "out", alias: "o", type: String, - typeLabel: `FILE`, - description: "The output file. Determines --lang and --top-level." + typeLabel: "FILE", + description: "The output file. Determines --lang and --top-level.", }, { name: "top-level", alias: "t", type: String, typeLabel: "NAME", - description: "The name for the top level type." - } + description: "The name for the top level type.", + }, ]; const lang: OptionDefinition[] = targetLanguages.length < 2 ? [] : [ - { - name: "lang", - alias: "l", - type: String, - typeLabel: "LANG", - description: "The target language." - } - ]; + { + name: "lang", + alias: "l", + type: String, + typeLabel: "LANG", + description: "The target language.", + }, + ]; const afterLang: OptionDefinition[] = [ { name: "src-lang", @@ -356,7 +363,7 @@ function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinit type: String, defaultValue: undefined, typeLabel: "SRC_LANG", - description: "The source language (default is json)." + description: "The source language (default is json).", }, { name: "src", @@ -364,49 +371,49 @@ function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinit multiple: true, defaultOption: true, typeLabel: "FILE|URL|DIRECTORY", - description: "The file, url, or data directory to type." + description: "The file, url, or data directory to type.", }, { name: "src-urls", type: String, typeLabel: "FILE", - description: "Tracery grammar describing URLs to crawl." - } + description: "Tracery grammar describing URLs to crawl.", + }, ]; const inference: OptionDefinition[] = Array.from( mapMap(mapFromObject(inferenceFlags), (flag, name) => { return { name: dashedFromCamelCase(negatedInferenceFlagName(name)), type: Boolean, - description: flag.negationDescription + "." + description: flag.negationDescription + ".", }; - }).values() + }).values(), ); const afterInference: OptionDefinition[] = [ { name: "graphql-schema", type: String, typeLabel: "FILE", - description: "GraphQL introspection file." + description: "GraphQL introspection file.", }, { name: "graphql-introspect", type: String, typeLabel: "URL", - description: "Introspect GraphQL schema from a server." + description: "Introspect GraphQL schema from a server.", }, { name: "http-method", type: String, typeLabel: "METHOD", - description: "HTTP method to use for the GraphQL introspection query." + description: "HTTP method to use for the GraphQL introspection query.", }, { name: "http-header", type: String, multiple: true, typeLabel: "HEADER", - description: "Header(s) to attach to all HTTP requests, including the GraphQL introspection query." + description: "Header(s) to attach to all HTTP requests, including the GraphQL introspection query.", }, { name: "additional-schema", @@ -414,67 +421,67 @@ function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinit type: String, multiple: true, typeLabel: "FILE", - description: "Register the $id's of additional JSON Schema files." + description: "Register the $id's of additional JSON Schema files.", }, { name: "no-render", type: Boolean, - description: "Don't render output." + description: "Don't render output.", }, { name: "alphabetize-properties", type: Boolean, - description: "Alphabetize order of class properties." + description: "Alphabetize order of class properties.", }, { name: "all-properties-optional", type: Boolean, - description: "Make all class properties optional." + description: "Make all class properties optional.", }, { name: "build-markov-chain", type: String, typeLabel: "FILE", - description: "Markov chain corpus filename." + description: "Markov chain corpus filename.", }, { name: "quiet", type: Boolean, - description: "Don't show issues in the generated code." + description: "Don't show issues in the generated code.", }, { name: "debug", type: String, typeLabel: "OPTIONS or all", description: - "Comma separated debug options: print-graph, print-reconstitution, print-gather-names, print-transformations, print-schema-resolving, print-times, provenance" + "Comma separated debug options: print-graph, print-reconstitution, print-gather-names, print-transformations, print-schema-resolving, print-times, provenance", }, { name: "telemetry", type: String, typeLabel: "enable|disable", - description: "Enable anonymous telemetry to help improve quicktype" + description: "Enable anonymous telemetry to help improve quicktype", }, { name: "help", alias: "h", type: Boolean, - description: "Get some help." + description: "Get some help.", }, { name: "version", alias: "v", type: Boolean, - description: "Display the version of quicktype" - } + description: "Display the version of quicktype", + }, ]; return beforeLang.concat(lang, afterLang, inference, afterInference); } interface ColumnDefinition { name: string; + padding?: { left: string, right: string, }; width?: number; - padding?: { left: string; right: string }; } interface TableOptions { @@ -482,27 +489,27 @@ interface TableOptions { } interface UsageSection { - header?: string; content?: string | string[]; + header?: string; + hide?: string[]; optionList?: OptionDefinition[]; tableOptions?: TableOptions; - hide?: string[]; } const tableOptionsForOptions: TableOptions = { columns: [ { name: "option", - width: 60 + width: 60, }, { name: "description", - width: 60 - } - ] + width: 60, + }, + ], }; -function makeSectionsBeforeRenderers(targetLanguages: TargetLanguage[]): UsageSection[] { +function makeSectionsBeforeRenderers (targetLanguages: TargetLanguage[]): UsageSection[] { const langDisplayNames = targetLanguages.map(r => r.displayName).join(", "); return [ @@ -510,24 +517,24 @@ function makeSectionsBeforeRenderers(targetLanguages: TargetLanguage[]): UsageSe header: "Synopsis", content: [ `$ quicktype [${chalk.bold("--lang")} LANG] [${chalk.bold("--src-lang")} SRC_LANG] [${chalk.bold( - "--out" + "--out", )} FILE] FILE|URL ...`, "", ` LANG ... ${makeLangTypeLabel(targetLanguages)}`, "", - "SRC_LANG ... json|schema|graphql|postman|typescript" - ] + "SRC_LANG ... json|schema|graphql|postman|typescript", + ], }, { header: "Description", - content: `Given JSON sample data, quicktype outputs code for working with that data in ${langDisplayNames}.` + content: `Given JSON sample data, quicktype outputs code for working with that data in ${langDisplayNames}.`, }, { header: "Options", optionList: makeOptionDefinitions(targetLanguages), hide: ["no-render", "build-markov-chain"], - tableOptions: tableOptionsForOptions - } + tableOptions: tableOptionsForOptions, + }, ]; } @@ -544,21 +551,21 @@ const sectionsAfterRenderers: UsageSection[] = [ + Bar - bar-sample-1.json - bar-sample-2.json - - Baz.url` + - Baz.url`, ), "$ quicktype -l go samples", "", chalk.dim("Generate JSON Schema, then TypeScript"), "$ quicktype -o schema.json https://blockchain.info/latestblock", - "$ quicktype -o bitcoin.ts --src-lang schema schema.json" - ] + "$ quicktype -o bitcoin.ts --src-lang schema schema.json", + ], }, { - content: `Learn more at ${chalk.bold("quicktype.io")}` - } + content: `Learn more at ${chalk.bold("quicktype.io")}`, + }, ]; -export function parseCLIOptions(argv: string[], targetLanguage?: TargetLanguage): CLIOptions { +export function parseCLIOptions (argv: string[], targetLanguage?: TargetLanguage): CLIOptions { if (argv.length === 0) { return inferCLIOptions({ help: true }, targetLanguage); } @@ -574,6 +581,7 @@ export function parseCLIOptions(argv: string[], targetLanguage?: TargetLanguage) if (targetLanguage === undefined) { targetLanguage = getTargetLanguage(incompleteOptions.lang); } + const rendererOptionDefinitions = targetLanguage.cliOptionDefinitions.actual; // Use the global options as well as the renderer options from now on: const allOptionDefinitions = _.concat(optionDefinitions, rendererOptionDefinitions); @@ -584,23 +592,24 @@ export function parseCLIOptions(argv: string[], targetLanguage?: TargetLanguage) // Parse the options in argv and split them into global options and renderer options, // according to each option definition's `renderer` field. If `partial` is false this // will throw if it encounters an unknown option. -function parseOptions(definitions: OptionDefinition[], argv: string[], partial: boolean): Partial { - let opts: { [key: string]: any }; +function parseOptions (definitions: OptionDefinition[], argv: string[], partial: boolean): Partial { + let opts: { [key: string]: any, }; try { opts = commandLineArgs(definitions, { argv, partial }); } catch (e) { assert(!partial, "Partial option parsing should not have failed"); return messageError("DriverCLIOptionParsingFailed", { message: exceptionToString(e) }); } + for (const k of Object.keys(opts)) { if (opts[k] === null) { return messageError("DriverCLIOptionParsingFailed", { - message: `Missing value for command line option "${k}"` + message: `Missing value for command line option "${k}"`, }); } } - const options: { rendererOptions: RendererOptions; [key: string]: any } = { rendererOptions: {} }; + const options: { [key: string]: any, rendererOptions: RendererOptions, } = { rendererOptions: {} }; for (const o of definitions) { if (!hasOwnProperty(opts, o.name)) continue; const v = opts[o.name] as string; @@ -610,10 +619,11 @@ function parseOptions(definitions: OptionDefinition[], argv: string[], partial: options[k] = v; } } + return options; } -function usage(targetLanguages: TargetLanguage[]) { +function usage (targetLanguages: TargetLanguage[]) { const rendererSections: UsageSection[] = []; for (const language of targetLanguages) { @@ -623,7 +633,7 @@ function usage(targetLanguages: TargetLanguage[]) { rendererSections.push({ header: `Options for ${language.displayName}`, optionList: definitions, - tableOptions: tableOptionsForOptions + tableOptions: tableOptionsForOptions, }); } @@ -633,12 +643,12 @@ function usage(targetLanguages: TargetLanguage[]) { } // Returns an array of [name, sourceURIs] pairs. -async function getSourceURIs(options: CLIOptions): Promise<[string, string[]][]> { +async function getSourceURIs (options: CLIOptions): Promise> { if (options.srcUrls !== undefined) { const json = parseJSON( await readFromFileOrURL(options.srcUrls, options.httpHeader), "URL grammar", - options.srcUrls + options.srcUrls, ); const jsonMap = urlsFromURLGrammar(json); const topLevels = Object.getOwnPropertyNames(jsonMap); @@ -650,7 +660,7 @@ async function getSourceURIs(options: CLIOptions): Promise<[string, string[]][]> } } -async function typeSourcesForURIs(name: string, uris: string[], options: CLIOptions): Promise { +async function typeSourcesForURIs (name: string, uris: string[], options: CLIOptions): Promise { switch (options.srcLang) { case "json": return [await sourceFromFileOrUrlArray(name, uris, options.httpHeader)]; @@ -661,10 +671,10 @@ async function typeSourcesForURIs(name: string, uris: string[], options: CLIOpti } } -async function getSources(options: CLIOptions): Promise { +async function getSources (options: CLIOptions): Promise { const sourceURIs = await getSourceURIs(options); const sourceArrays = await Promise.all( - sourceURIs.map(async ([name, uris]) => await typeSourcesForURIs(name, uris, options)) + sourceURIs.map(async ([name, uris]) => await typeSourcesForURIs(name, uris, options)), ); let sources: TypeSource[] = ([] as TypeSource[]).concat(...sourceArrays); @@ -678,34 +688,35 @@ async function getSources(options: CLIOptions): Promise { // Every src that's not a directory is assumed to be a file or URL const filesOrUrls = options.src.filter(x => !_.includes(directories, x)); if (!_.isEmpty(filesOrUrls)) { - sources.push(...(await typeSourcesForURIs(options.topLevel, filesOrUrls, options))); + sources.push(...await typeSourcesForURIs(options.topLevel, filesOrUrls, options)); } return sources; } -function makeTypeScriptSource(fileNames: string[]): SchemaTypeSource { +function makeTypeScriptSource (fileNames: string[]): SchemaTypeSource { return Object.assign({ kind: "schema" }, schemaForTypeScriptSources(fileNames)) as SchemaTypeSource; } -export function jsonInputForTargetLanguage( +export function jsonInputForTargetLanguage ( targetLanguage: string | TargetLanguage, languages?: TargetLanguage[], - handleJSONRefs = false + handleJSONRefs = false, ): JSONInput { if (typeof targetLanguage === "string") { targetLanguage = defined(languageNamed(targetLanguage, languages)); } + const compressedJSON = new CompressedJSONFromStream(targetLanguage.dateTimeRecognizer, handleJSONRefs); return new JSONInput(compressedJSON); } -async function makeInputData( +async function makeInputData ( sources: TypeSource[], targetLanguage: TargetLanguage, - additionalSchemaAddresses: ReadonlyArray, + additionalSchemaAddresses: readonly string[], handleJSONRefs: boolean, - httpHeaders?: string[] + httpHeaders?: string[], ): Promise { const inputData = new InputData(); @@ -716,14 +727,14 @@ async function makeInputData( break; case "json": await inputData.addSource("json", source, () => - jsonInputForTargetLanguage(targetLanguage, undefined, handleJSONRefs) + jsonInputForTargetLanguage(targetLanguage, undefined, handleJSONRefs), ); break; case "schema": await inputData.addSource( "schema", source, - () => new JSONSchemaInput(new FetchingJSONSchemaStore(httpHeaders), [], additionalSchemaAddresses) + () => new JSONSchemaInput(new FetchingJSONSchemaStore(httpHeaders), [], additionalSchemaAddresses), ); break; default: @@ -734,23 +745,25 @@ async function makeInputData( return inputData; } -function stringSourceDataToStreamSourceData(src: JSONSourceData): JSONSourceData { +function stringSourceDataToStreamSourceData (src: JSONSourceData): JSONSourceData { return { name: src.name, description: src.description, samples: src.samples.map(stringToStream) }; } -export async function makeQuicktypeOptions( +export async function makeQuicktypeOptions ( options: CLIOptions, - targetLanguages?: TargetLanguage[] + targetLanguages?: TargetLanguage[], ): Promise | undefined> { if (options.help) { usage(targetLanguages === undefined ? defaultTargetLanguages : targetLanguages); return undefined; } + if (options.version) { console.log(`quicktype version ${packageJSON.version}`); console.log("Visit quicktype.io for more info."); return undefined; } + if (options.buildMarkovChain !== undefined) { const contents = fs.readFileSync(options.buildMarkovChain).toString(); const lines = contents.split("\n"); @@ -770,27 +783,31 @@ export async function makeQuicktypeOptions( schemaString = await introspectServer( options.graphqlIntrospect, withDefault(options.httpMethod, "POST"), - withDefault(options.httpHeader, []) + withDefault(options.httpHeader, []), ); if (options.graphqlSchema !== undefined) { fs.writeFileSync(options.graphqlSchema, schemaString); wroteSchemaToFile = true; } } + const numSources = options.src.length; if (numSources !== 1) { if (wroteSchemaToFile) { // We're done. return undefined; } + if (numSources === 0) { if (schemaString !== undefined) { console.log(schemaString); return undefined; } + return messageError("DriverNoGraphQLQueryGiven", {}); } } + const gqlSources: GraphQLTypeSource[] = []; for (const queryFile of options.src) { let schemaFileName: string | undefined = undefined; @@ -798,11 +815,13 @@ export async function makeQuicktypeOptions( schemaFileName = defined(options.graphqlSchema); schemaString = fs.readFileSync(schemaFileName, "utf8"); } + const schema = parseJSON(schemaString, "GraphQL schema", schemaFileName); const query = await getStream(await readableFromFileOrURL(queryFile, options.httpHeader)); const name = numSources === 1 ? options.topLevel : typeNameFromFilename(queryFile); gqlSources.push({ kind: "graphql", name, schema, query }); } + sources = gqlSources; break; case "json": @@ -817,27 +836,30 @@ export async function makeQuicktypeOptions( const collectionJSON = fs.readFileSync(collectionFile, "utf8"); const { sources: postmanSources, description } = sourcesFromPostmanCollection( collectionJSON, - collectionFile + collectionFile, ); for (const src of postmanSources) { sources.push( - Object.assign({ kind: "json" }, stringSourceDataToStreamSourceData(src)) as JSONTypeSource + Object.assign({ kind: "json" }, stringSourceDataToStreamSourceData(src)) as JSONTypeSource, ); } + if (postmanSources.length > 1) { fixedTopLevels = true; } + if (description !== undefined) { leadingComments = wordWrap(description).split("\n"); } } + break; default: return messageError("DriverUnknownSourceLanguage", { lang: options.srcLang }); } const components = definedMap(options.debug, d => d.split(",")); - const debugAll = components !== undefined && components.indexOf("all") >= 0; + const debugAll = components !== undefined && components.includes("all"); let debugPrintGraph = debugAll; let checkProvenance = debugAll; let debugPrintReconstitution = debugAll; @@ -888,7 +910,7 @@ export async function makeQuicktypeOptions( debugPrintGatherNames, debugPrintTransformations, debugPrintSchemaResolving, - debugPrintTimes + debugPrintTimes, }; for (const flagName of inferenceFlagNames) { const cliName = negatedInferenceFlagName(flagName); @@ -905,15 +927,15 @@ export async function makeQuicktypeOptions( lang, options.additionalSchema, quicktypeOptions.ignoreJsonRefs !== true, - options.httpHeader + options.httpHeader, ); return quicktypeOptions; } -export function writeOutput( +export function writeOutput ( cliOptions: CLIOptions, - resultsByFilename: ReadonlyMap + resultsByFilename: ReadonlyMap, ): void { let onFirst = true; for (const [filename, { lines, annotations }] of resultsByFilename) { @@ -925,14 +947,18 @@ export function writeOutput( if (!onFirst) { process.stdout.write("\n"); } + if (resultsByFilename.size > 1) { process.stdout.write(`// ${filename}\n\n`); } + process.stdout.write(output); } + if (cliOptions.quiet) { continue; } + for (const sa of annotations) { const annotation = sa.annotation; if (!(annotation instanceof IssueAnnotationData)) continue; @@ -946,7 +972,7 @@ export function writeOutput( } } -export async function main(args: string[] | Partial) { +export async function main (args: string[] | Partial) { let cliOptions: CLIOptions; if (Array.isArray(args)) { cliOptions = parseCLIOptions(args); @@ -964,6 +990,7 @@ export async function main(args: string[] | Partial) { console.error(chalk.red("telemetry must be 'enable' or 'disable'")); return; } + if (Array.isArray(args) && args.length === 2) { // This was merely a CLI run to set telemetry and we should not proceed return; @@ -985,6 +1012,7 @@ if (require.main === module) { } else { console.error(e); } + process.exit(1); }); } From 392838a1e8c2bf243d7b03aacaf86ff926339592 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 8 Apr 2024 07:49:22 -0700 Subject: [PATCH 07/80] update eslint rules, eslintignore --- .eslintignore | 6 ++++++ .eslintrc.json | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..0fd88d904 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +dist +node_modules +packages/*/dist +packages/*/node_modules +test/runs +test/input diff --git a/.eslintrc.json b/.eslintrc.json index 922bb451a..1f7f67937 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,20 +12,28 @@ }, "plugins": ["canonical"], "rules": { + "comma-dangle": "off", + "no-extra-parens": "off", "canonical/prefer-inline-type-import": "error", + "@typescript-eslint/class-literal-property-style": "off", + "@typescript-eslint/comma-dangle": "off", "@typescript-eslint/consistent-type-definitions": ["error", "interface"], "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }], "@typescript-eslint/explicit-function-return-type": "warn", "@typescript-eslint/indent": ["error", 4], - "@typescript-eslint/quotes": ["error", "double"], - "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], + "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true }], + "@typescript-eslint/member-delimiter-style": "off", "@typescript-eslint/naming-convention": "error", "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/no-extra-parens": "off", + "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], "@typescript-eslint/no-unused-vars": ["error", { "vars": "local", "args": "none" }], "@typescript-eslint/no-use-before-define": "warn", "@typescript-eslint/no-useless-empty-export": "error", "@typescript-eslint/prefer-readonly": "warn", "@typescript-eslint/prefer-reduce-type-parameter": "off", + "@typescript-eslint/require-array-sort-compare": "off", + "@typescript-eslint/space-before-function-paren": "off", "@typescript-eslint/switch-exhaustiveness-check": "error", "@typescript-eslint/unified-signatures": "error" }, From d9baf6ea6e6582771000d1ad77705e8e7bd0df2a Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 8 Apr 2024 07:49:31 -0700 Subject: [PATCH 08/80] add lint:fix script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f221ca9ed..8b6d27c96 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "start": "script/watch", "clean": "rm -rf dist node_modules *~ packages/*/{dist,node_modules}", "debug": "node --inspect-brk --max-old-space-size=4096 ./dist/index.js", - "lint": "eslint src/** packages/*/src/**" + "lint": "eslint src/** packages/*/src/**", + "lint:fix": "eslint --fix src/** packages/*/src/**" }, "workspaces": [ "./packages/quicktype-core", From 8bbabf127ec47194450fbd09bef68fb82e813d67 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 8 Apr 2024 07:49:22 -0700 Subject: [PATCH 09/80] update eslint rules, eslintignore --- .eslintignore | 6 ++++++ .eslintrc.json | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..0fd88d904 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +dist +node_modules +packages/*/dist +packages/*/node_modules +test/runs +test/input diff --git a/.eslintrc.json b/.eslintrc.json index 922bb451a..1f7f67937 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,20 +12,28 @@ }, "plugins": ["canonical"], "rules": { + "comma-dangle": "off", + "no-extra-parens": "off", "canonical/prefer-inline-type-import": "error", + "@typescript-eslint/class-literal-property-style": "off", + "@typescript-eslint/comma-dangle": "off", "@typescript-eslint/consistent-type-definitions": ["error", "interface"], "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }], "@typescript-eslint/explicit-function-return-type": "warn", "@typescript-eslint/indent": ["error", 4], - "@typescript-eslint/quotes": ["error", "double"], - "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], + "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true }], + "@typescript-eslint/member-delimiter-style": "off", "@typescript-eslint/naming-convention": "error", "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/no-extra-parens": "off", + "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], "@typescript-eslint/no-unused-vars": ["error", { "vars": "local", "args": "none" }], "@typescript-eslint/no-use-before-define": "warn", "@typescript-eslint/no-useless-empty-export": "error", "@typescript-eslint/prefer-readonly": "warn", "@typescript-eslint/prefer-reduce-type-parameter": "off", + "@typescript-eslint/require-array-sort-compare": "off", + "@typescript-eslint/space-before-function-paren": "off", "@typescript-eslint/switch-exhaustiveness-check": "error", "@typescript-eslint/unified-signatures": "error" }, From f1d19aa4bd6a697c19d047a339391dfdc7cda824 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 8 Apr 2024 07:49:31 -0700 Subject: [PATCH 10/80] add lint:fix script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f221ca9ed..8b6d27c96 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "start": "script/watch", "clean": "rm -rf dist node_modules *~ packages/*/{dist,node_modules}", "debug": "node --inspect-brk --max-old-space-size=4096 ./dist/index.js", - "lint": "eslint src/** packages/*/src/**" + "lint": "eslint src/** packages/*/src/**", + "lint:fix": "eslint --fix src/** packages/*/src/**" }, "workspaces": [ "./packages/quicktype-core", From 994567ec355c1dbfc4eb6abe9073b2a6085eb5aa Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 8 Apr 2024 08:50:01 -0700 Subject: [PATCH 11/80] add import rules --- .eslintrc.json | 17 +++++++++++++++-- package.json | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 1f7f67937..fcf73b84b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,16 +5,29 @@ "files": "*.json" }, { - "extends": ["eslint:recommended", "canonical/typescript", "canonical/typescript-type-checking"], + "extends": [ + "eslint:recommended", + "canonical/typescript", + "canonical/typescript-type-checking", + "plugin:import/recommended", + "plugin:import/typescript" + ], + "plugins": ["canonical"], "parserOptions": { "tsconfigRootDir": "./", "project": ["./tsconfig.json", "./packages/*/tsconfig.json"] }, - "plugins": ["canonical"], + "settings": { + "import/resolver": { + "typescript": true, + "node": true + } + }, "rules": { "comma-dangle": "off", "no-extra-parens": "off", "canonical/prefer-inline-type-import": "error", + "typescript-sort-keys/string-enum": "off", "@typescript-eslint/class-literal-property-style": "off", "@typescript-eslint/comma-dangle": "off", "@typescript-eslint/consistent-type-definitions": ["error", "interface"], diff --git a/package.json b/package.json index 8b6d27c96..17ee5b728 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "eslint": "^8.57.0", "eslint-config-canonical": "^41.1.7", "eslint-config-prettier": "^6.10.0", - "eslint-import-resolver-typescript": "^3.5.2", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-canonical": "^3.4.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-json": "^3.1.0", From d2598745687de27654bb8bfba4beb1d0cd7adb86 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 8 Apr 2024 08:50:01 -0700 Subject: [PATCH 12/80] add import rules --- .eslintrc.json | 17 +++++++++++++++-- package.json | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 1f7f67937..fcf73b84b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,16 +5,29 @@ "files": "*.json" }, { - "extends": ["eslint:recommended", "canonical/typescript", "canonical/typescript-type-checking"], + "extends": [ + "eslint:recommended", + "canonical/typescript", + "canonical/typescript-type-checking", + "plugin:import/recommended", + "plugin:import/typescript" + ], + "plugins": ["canonical"], "parserOptions": { "tsconfigRootDir": "./", "project": ["./tsconfig.json", "./packages/*/tsconfig.json"] }, - "plugins": ["canonical"], + "settings": { + "import/resolver": { + "typescript": true, + "node": true + } + }, "rules": { "comma-dangle": "off", "no-extra-parens": "off", "canonical/prefer-inline-type-import": "error", + "typescript-sort-keys/string-enum": "off", "@typescript-eslint/class-literal-property-style": "off", "@typescript-eslint/comma-dangle": "off", "@typescript-eslint/consistent-type-definitions": ["error", "interface"], diff --git a/package.json b/package.json index 8b6d27c96..17ee5b728 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "eslint": "^8.57.0", "eslint-config-canonical": "^41.1.7", "eslint-config-prettier": "^6.10.0", - "eslint-import-resolver-typescript": "^3.5.2", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-canonical": "^3.4.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-json": "^3.1.0", From 291f5c9ffd10de87f79d173087ef48eafd922a70 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 00:05:51 -0700 Subject: [PATCH 13/80] update import rules --- .eslintrc.json | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index fcf73b84b..c14276ec1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,8 @@ "eslint:recommended", "canonical/typescript", "canonical/typescript-type-checking", - "plugin:import/recommended", + "plugin:import/errors", + "plugin:import/warnings", "plugin:import/typescript" ], "plugins": ["canonical"], @@ -28,6 +29,41 @@ "no-extra-parens": "off", "canonical/prefer-inline-type-import": "error", "typescript-sort-keys/string-enum": "off", + + "sort-imports": [ + "error", + { + "ignoreDeclarationSort": true + } + ], + "no-duplicate-imports": "error", + "import/first": "error", + "import/order": [ + "error", + { + "newlines-between": "always", + "groups": ["builtin", "external", "internal", "parent", "sibling", "index", "object", "type"], + "pathGroups": [ + { + "pattern": "@/**", + "group": "internal", + "position": "before" + } + ], + "alphabetize": { + "order": "asc" /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */, + "caseInsensitive": true /* ignore case. Options: [true, false] */ + } + } + ], + + "import/no-absolute-path": "error", + "import/no-cycle": "error", + "import/no-duplicates": "error", + "import/no-extraneous-dependencies": "error", + "import/no-named-as-default": "off", + "import/no-useless-path-segments": "error", + "@typescript-eslint/class-literal-property-style": "off", "@typescript-eslint/comma-dangle": "off", "@typescript-eslint/consistent-type-definitions": ["error", "interface"], From 03d80012266b6eb30b2fdd25d82fc1b061afd592 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 09:28:49 -0700 Subject: [PATCH 14/80] reduce excess style rules --- .eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index c14276ec1..a5cf75933 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -69,10 +69,11 @@ "@typescript-eslint/consistent-type-definitions": ["error", "interface"], "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }], "@typescript-eslint/explicit-function-return-type": "warn", - "@typescript-eslint/indent": ["error", 4], + "@typescript-eslint/indent": "off", "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true }], "@typescript-eslint/member-delimiter-style": "off", "@typescript-eslint/naming-convention": "error", + "@typescript-eslint/no-base-to-string": "warn", "@typescript-eslint/no-empty-interface": "warn", "@typescript-eslint/no-extra-parens": "off", "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], From 99dd240f246f2fc9c473b06e5191e0990c02c117 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 20:26:39 -0700 Subject: [PATCH 15/80] downgrade remaining to warnings --- .eslintignore | 2 ++ .eslintrc.json | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.eslintignore b/.eslintignore index 0fd88d904..135b09976 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,5 @@ packages/*/dist packages/*/node_modules test/runs test/input + +license diff --git a/.eslintrc.json b/.eslintrc.json index a5cf75933..f35b5c03c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -27,6 +27,8 @@ "rules": { "comma-dangle": "off", "no-extra-parens": "off", + "no-case-declarations": "warn", + "no-duplicate-imports": "error", "canonical/prefer-inline-type-import": "error", "typescript-sort-keys/string-enum": "off", @@ -36,7 +38,6 @@ "ignoreDeclarationSort": true } ], - "no-duplicate-imports": "error", "import/first": "error", "import/order": [ "error", @@ -72,10 +73,10 @@ "@typescript-eslint/indent": "off", "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true }], "@typescript-eslint/member-delimiter-style": "off", - "@typescript-eslint/naming-convention": "error", "@typescript-eslint/no-base-to-string": "warn", "@typescript-eslint/no-empty-interface": "warn", "@typescript-eslint/no-extra-parens": "off", + "@typescript-eslint/no-loop-func": "warn", "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], "@typescript-eslint/no-unused-vars": ["error", { "vars": "local", "args": "none" }], "@typescript-eslint/no-use-before-define": "warn", @@ -85,6 +86,7 @@ "@typescript-eslint/require-array-sort-compare": "off", "@typescript-eslint/space-before-function-paren": "off", "@typescript-eslint/switch-exhaustiveness-check": "error", + "@typescript-eslint/unbound-method": "warn", "@typescript-eslint/unified-signatures": "error" }, "overrides": [ From 7f22254f300ea60eba532c3ccc568abc6e652eed Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 8 Apr 2024 08:50:12 -0700 Subject: [PATCH 16/80] fix enum values fixup! fix enum values --- .../src/input/CompressedJSON.ts | 97 +-- .../src/input/JSONSchemaInput.ts | 252 +++--- packages/quicktype-core/src/language/CJSON.ts | 787 +++++++++--------- .../quicktype-core/src/language/CPlusPlus.ts | 775 ++++++++--------- .../quicktype-core/src/language/CSharp.ts | 492 ++++++----- .../quicktype-core/src/language/Kotlin.ts | 288 ++++--- packages/quicktype-core/src/language/Rust.ts | 140 ++-- .../quicktype-core/src/language/Scala3.ts | 170 ++-- .../quicktype-core/src/language/Smithy4s.ts | 132 +-- 9 files changed, 1553 insertions(+), 1580 deletions(-) diff --git a/packages/quicktype-core/src/input/CompressedJSON.ts b/packages/quicktype-core/src/input/CompressedJSON.ts index 7832c0675..069834913 100644 --- a/packages/quicktype-core/src/input/CompressedJSON.ts +++ b/packages/quicktype-core/src/input/CompressedJSON.ts @@ -1,23 +1,23 @@ import { addHashCode, hashCodeInit, hashString } from "collection-utils"; import { defined, panic, assert } from "../support/Support"; -import { type TransformedStringTypeKind} from "../Type"; +import { type TransformedStringTypeKind } from "../Type"; import { isPrimitiveStringTypeKind, transformedStringTypeTargetTypeKindsMap } from "../Type"; import { type DateTimeRecognizer } from "../DateTime"; import { inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; export enum Tag { - Null, - False, - True, - Integer, - Double, - InternedString, - UninternedString, - Object, - Array, - StringFormat, - TransformedString + Null = 1, + False = 2, + True = 3, + Integer = 4, + Double = 5, + InternedString = 6, + UninternedString = 7, + Object = 8, + Array = 9, + StringFormat = 10, + TransformedString = 11 } export type Value = number; @@ -25,16 +25,16 @@ export type Value = number; const TAG_BITS = 4; const TAG_MASK = (1 << TAG_BITS) - 1; -export function makeValue (t: Tag, index: number): Value { - return t | index << TAG_BITS; +export function makeValue(t: Tag, index: number): Value { + return t | (index << TAG_BITS); } -function getIndex (v: Value, tag: Tag): number { +function getIndex(v: Value, tag: Tag): number { assert(valueTag(v) === tag, "Trying to get index for value with invalid tag"); return v >> TAG_BITS; } -export function valueTag (v: Value): Tag { +export function valueTag(v: Value): Tag { return v & TAG_MASK; } @@ -54,21 +54,24 @@ export abstract class CompressedJSON { private _strings: string[] = []; - private _stringIndexes: { [str: string]: number, } = {}; + private _stringIndexes: { [str: string]: number } = {}; private _objects: Value[][] = []; private _arrays: Value[][] = []; - constructor (readonly dateTimeRecognizer: DateTimeRecognizer, readonly handleRefs: boolean) {} + constructor( + readonly dateTimeRecognizer: DateTimeRecognizer, + readonly handleRefs: boolean + ) {} - abstract parse (input: T): Promise; + abstract parse(input: T): Promise; - parseSync (_input: T): Value { + parseSync(_input: T): Value { return panic("parseSync not implemented in CompressedJSON"); } - getStringForValue (v: Value): string { + getStringForValue(v: Value): string { const tag = valueTag(v); assert(tag === Tag.InternedString || tag === Tag.TransformedString); return this._strings[getIndex(v, tag)]; @@ -82,7 +85,7 @@ export abstract class CompressedJSON { return this._arrays[getIndex(v, Tag.Array)]; }; - getStringFormatTypeKind (v: Value): TransformedStringTypeKind { + getStringFormatTypeKind(v: Value): TransformedStringTypeKind { const kind = this._strings[getIndex(v, Tag.StringFormat)]; if (!isPrimitiveStringTypeKind(kind) || kind === "string") { return panic("Not a transformed string type kind"); @@ -91,11 +94,11 @@ export abstract class CompressedJSON { return kind; } - protected get context (): Context { + protected get context(): Context { return defined(this._ctx); } - protected internString (s: string): number { + protected internString(s: string): number { if (Object.prototype.hasOwnProperty.call(this._stringIndexes, s)) { return this._stringIndexes[s]; } @@ -106,13 +109,13 @@ export abstract class CompressedJSON { return index; } - protected makeString (s: string): Value { + protected makeString(s: string): Value { const value = makeValue(Tag.InternedString, this.internString(s)); assert(typeof value === "number", `Interned string value is not a number: ${value}`); return value; } - protected internObject (obj: Value[]): Value { + protected internObject(obj: Value[]): Value { const index = this._objects.length; this._objects.push(obj); return makeValue(Tag.Object, index); @@ -124,16 +127,16 @@ export abstract class CompressedJSON { return makeValue(Tag.Array, index); }; - protected get isExpectingRef (): boolean { + protected get isExpectingRef(): boolean { return this._ctx !== undefined && this._ctx.currentKey === "$ref"; } - protected commitValue (value: Value): void { + protected commitValue(value: Value): void { assert(typeof value === "number", `CompressedJSON value is not a number: ${value}`); if (this._ctx === undefined) { assert( this._rootValue === undefined, - "Committing value but nowhere to commit to - root value still there.", + "Committing value but nowhere to commit to - root value still there." ); this._rootValue = value; } else if (this._ctx.currentObject !== undefined) { @@ -150,20 +153,20 @@ export abstract class CompressedJSON { } } - protected commitNull (): void { + protected commitNull(): void { this.commitValue(makeValue(Tag.Null, 0)); } - protected commitBoolean (v: boolean): void { + protected commitBoolean(v: boolean): void { this.commitValue(makeValue(v ? Tag.True : Tag.False, 0)); } - protected commitNumber (isDouble: boolean): void { + protected commitNumber(isDouble: boolean): void { const numberTag = isDouble ? Tag.Double : Tag.Integer; this.commitValue(makeValue(numberTag, 0)); } - protected commitString (s: string): void { + protected commitString(s: string): void { let value: Value | undefined = undefined; if (this.handleRefs && this.isExpectingRef) { value = this.makeString(s); @@ -185,7 +188,7 @@ export abstract class CompressedJSON { this.commitValue(value); } - protected finish (): Value { + protected finish(): Value { const value = this._rootValue; if (value === undefined) { return panic("Finished without root document"); @@ -196,7 +199,7 @@ export abstract class CompressedJSON { return value; } - protected pushContext (): void { + protected pushContext(): void { if (this._ctx !== undefined) { this._contextStack.push(this._ctx); } @@ -205,21 +208,21 @@ export abstract class CompressedJSON { currentObject: undefined, currentArray: undefined, currentKey: undefined, - currentNumberIsDouble: false, + currentNumberIsDouble: false }; } - protected pushObjectContext (): void { + protected pushObjectContext(): void { this.pushContext(); defined(this._ctx).currentObject = []; } - protected setPropertyKey (key: string): void { + protected setPropertyKey(key: string): void { const ctx = this.context; ctx.currentKey = key; } - protected finishObject (): void { + protected finishObject(): void { const obj = this.context.currentObject; if (obj === undefined) { return panic("Object ended but not started"); @@ -229,12 +232,12 @@ export abstract class CompressedJSON { this.commitValue(this.internObject(obj)); } - protected pushArrayContext (): void { + protected pushArrayContext(): void { this.pushContext(); defined(this._ctx).currentArray = []; } - protected finishArray (): void { + protected finishArray(): void { const arr = this.context.currentArray; if (arr === undefined) { return panic("Array ended but not started"); @@ -244,16 +247,16 @@ export abstract class CompressedJSON { this.commitValue(this.internArray(arr)); } - protected popContext (): void { + protected popContext(): void { assert(this._ctx !== undefined, "Popping context when there isn't one"); this._ctx = this._contextStack.pop(); } - equals (other: any): boolean { + equals(other: any): boolean { return this === other; } - hashCode (): number { + hashCode(): number { let hashAccumulator = hashCodeInit; for (const s of this._strings) { hashAccumulator = addHashCode(hashAccumulator, hashString(s)); @@ -281,17 +284,17 @@ export abstract class CompressedJSON { } export class CompressedJSONFromString extends CompressedJSON { - async parse (input: string): Promise { + async parse(input: string): Promise { return this.parseSync(input); } - parseSync (input: string): Value { + parseSync(input: string): Value { const json = JSON.parse(input); this.process(json); return this.finish(); } - private process (json: unknown): void { + private process(json: unknown): void { if (json === null) { this.commitNull(); } else if (typeof json === "boolean") { diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index ae8f4b5fd..d3226c949 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -18,29 +18,19 @@ import { definedMap, addHashCode, iterableFirst, - hashString, + hashString } from "collection-utils"; -import { - type PrimitiveTypeKind, - type TransformedStringTypeKind} from "../Type"; -import { - transformedStringTypeTargetTypeKindsMap, - isNumberTypeKind, -} from "../Type"; -import { type StringMap} from "../support/Support"; +import { type PrimitiveTypeKind, type TransformedStringTypeKind } from "../Type"; +import { transformedStringTypeTargetTypeKindsMap, isNumberTypeKind } from "../Type"; +import { type StringMap } from "../support/Support"; import { panic, assertNever, assert, defined, parseJSON } from "../support/Support"; import { type TypeBuilder } from "../TypeBuilder"; import { TypeNames } from "../attributes/TypeNames"; import { makeNamesTypeAttributes, modifyTypeNames, singularizeTypeNames } from "../attributes/TypeNames"; -import { - type TypeAttributes} from "../attributes/TypeAttributes"; -import { - makeTypeAttributesInferred, - emptyTypeAttributes, - combineTypeAttributes, -} from "../attributes/TypeAttributes"; -import { type JSONSchema} from "./JSONSchemaStore"; +import { type TypeAttributes } from "../attributes/TypeAttributes"; +import { makeTypeAttributesInferred, emptyTypeAttributes, combineTypeAttributes } from "../attributes/TypeAttributes"; +import { type JSONSchema } from "./JSONSchemaStore"; import { JSONSchemaStore } from "./JSONSchemaStore"; import { messageAssert, messageError } from "../Messages"; import { StringTypes } from "../attributes/StringTypes"; @@ -61,24 +51,24 @@ import { patternAttributeProducer } from "../attributes/Constraints"; import { uriSchemaAttributesProducer } from "../attributes/URIAttributes"; export enum PathElementKind { - Root, - KeyOrIndex, - Type, - Object + Root = 1, + KeyOrIndex = 2, + Type = 3, + Object = 4 } export type PathElement = - | { kind: PathElementKind.Root, } - | { key: string, kind: PathElementKind.KeyOrIndex, } - | { index: number, kind: PathElementKind.Type, } - | { kind: PathElementKind.Object, }; + | { kind: PathElementKind.Root } + | { key: string; kind: PathElementKind.KeyOrIndex } + | { index: number; kind: PathElementKind.Type } + | { kind: PathElementKind.Object }; -function keyOrIndex (pe: PathElement): string | undefined { +function keyOrIndex(pe: PathElement): string | undefined { if (pe.kind !== PathElementKind.KeyOrIndex) return undefined; return pe.key; } -function pathElementEquals (a: PathElement, b: PathElement): boolean { +function pathElementEquals(a: PathElement, b: PathElement): boolean { if (a.kind !== b.kind) return false; switch (a.kind) { case PathElementKind.Type: @@ -90,15 +80,15 @@ function pathElementEquals (a: PathElement, b: PathElement): boolean { } } -function withRef (refOrLoc: Ref | (() => Ref) | Location): { ref: Ref, }; -function withRef (refOrLoc: Ref | (() => Ref) | Location, props?: T): T & { ref: Ref, }; -function withRef (refOrLoc: Ref | (() => Ref) | Location, props?: T): any { +function withRef(refOrLoc: Ref | (() => Ref) | Location): { ref: Ref }; +function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): T & { ref: Ref }; +function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): any { const ref = typeof refOrLoc === "function" ? refOrLoc() : refOrLoc instanceof Ref ? refOrLoc : refOrLoc.canonicalRef; return Object.assign({ ref }, props === undefined ? {} : props); } -function checkJSONSchemaObject (x: any, refOrLoc: Ref | (() => Ref)): StringMap { +function checkJSONSchemaObject(x: any, refOrLoc: Ref | (() => Ref)): StringMap { if (Array.isArray(x)) { return messageError("SchemaArrayIsInvalidSchema", withRef(refOrLoc)); } @@ -114,14 +104,14 @@ function checkJSONSchemaObject (x: any, refOrLoc: Ref | (() => Ref)): StringMap return x; } -function checkJSONSchema (x: any, refOrLoc: Ref | (() => Ref)): JSONSchema { +function checkJSONSchema(x: any, refOrLoc: Ref | (() => Ref)): JSONSchema { if (typeof x === "boolean") return x; return checkJSONSchemaObject(x, refOrLoc); } const numberRegexp = new RegExp("^[0-9]+$"); -function normalizeURI (uri: string | URI): URI { +function normalizeURI(uri: string | URI): URI { // FIXME: This is overly complicated and a bit shady. The problem is // that `normalize` will URL-escape, with the result that if we want to // open the URL as a file, escaped character will thwart us. I think the @@ -135,12 +125,12 @@ function normalizeURI (uri: string | URI): URI { } export class Ref { - static root (address: string | undefined): Ref { + static root(address: string | undefined): Ref { const uri = definedMap(address, a => new URI(a)); return new Ref(uri, []); } - private static parsePath (path: string): readonly PathElement[] { + private static parsePath(path: string): readonly PathElement[] { const elements: PathElement[] = []; if (path.startsWith("/")) { @@ -150,15 +140,13 @@ export class Ref { if (path !== "") { const parts = path.split("/"); - for (let i = 0; i < parts.length; i++) { - elements.push({ kind: PathElementKind.KeyOrIndex, key: parts[i] }); - } + parts.forEach(part => elements.push({ kind: PathElementKind.KeyOrIndex, key: part })); } return elements; } - static parseURI (uri: URI, destroyURI = false): Ref { + static parseURI(uri: URI, destroyURI = false): Ref { if (!destroyURI) { uri = uri.clone(); } @@ -173,15 +161,15 @@ export class Ref { return new Ref(uri, elements); } - static parse (ref: string): Ref { + static parse(ref: string): Ref { return Ref.parseURI(new URI(ref), true); } public addressURI: URI | undefined; - constructor ( + constructor( addressURI: URI | undefined, - readonly path: readonly PathElement[], + readonly path: readonly PathElement[] ) { if (addressURI !== undefined) { assert(addressURI.fragment() === "", `Ref URI with fragment is not allowed: ${addressURI.toString()}`); @@ -191,25 +179,25 @@ export class Ref { } } - get hasAddress (): boolean { + get hasAddress(): boolean { return this.addressURI !== undefined; } - get address (): string { + get address(): string { return defined(this.addressURI).toString(); } - get isRoot (): boolean { + get isRoot(): boolean { return this.path.length === 1 && this.path[0].kind === PathElementKind.Root; } - private pushElement (pe: PathElement): Ref { + private pushElement(pe: PathElement): Ref { const newPath = Array.from(this.path); newPath.push(pe); return new Ref(this.addressURI, newPath); } - push (...keys: string[]): Ref { + push(...keys: string[]): Ref { let ref: Ref = this; for (const key of keys) { ref = ref.pushElement({ kind: PathElementKind.KeyOrIndex, key }); @@ -218,15 +206,15 @@ export class Ref { return ref; } - pushObject (): Ref { + pushObject(): Ref { return this.pushElement({ kind: PathElementKind.Object }); } - pushType (index: number): Ref { + pushType(index: number): Ref { return this.pushElement({ kind: PathElementKind.Type, index }); } - resolveAgainst (base: Ref | undefined): Ref { + resolveAgainst(base: Ref | undefined): Ref { let addressURI = this.addressURI; if (base?.addressURI !== undefined) { addressURI = addressURI === undefined ? base.addressURI : addressURI.absoluteTo(base.addressURI); @@ -235,7 +223,7 @@ export class Ref { return new Ref(addressURI, this.path); } - get name (): string { + get name(): string { const path = Array.from(this.path); for (;;) { @@ -270,15 +258,15 @@ export class Ref { } } - get definitionName (): string | undefined { + get definitionName(): string | undefined { const pe = arrayGetFromEnd(this.path, 2); if (pe === undefined) return undefined; if (keyOrIndex(pe) === "definitions") return keyOrIndex(defined(arrayLast(this.path))); return undefined; } - toString (): string { - function elementToString (e: PathElement): string { + toString(): string { + function elementToString(e: PathElement): string { switch (e.kind) { case PathElementKind.Root: return ""; @@ -297,7 +285,7 @@ export class Ref { return address + "#" + this.path.map(elementToString).join("/"); } - private lookup (local: any, path: readonly PathElement[], root: JSONSchema): JSONSchema { + private lookup(local: any, path: readonly PathElement[], root: JSONSchema): JSONSchema { const refMaker = () => new Ref(this.addressURI, path); const first = path[0]; if (first === undefined) { @@ -330,24 +318,24 @@ export class Ref { } case PathElementKind.Type: - return panic("Cannot look up path that indexes \"type\""); + return panic('Cannot look up path that indexes "type"'); case PathElementKind.Object: - return panic("Cannot look up path that indexes \"object\""); + return panic('Cannot look up path that indexes "object"'); default: return assertNever(first); } } - lookupRef (root: JSONSchema): JSONSchema { + lookupRef(root: JSONSchema): JSONSchema { return this.lookup(root, this.path, root); } - equals (other: any): boolean { + equals(other: any): boolean { if (!(other instanceof Ref)) return false; if (this.addressURI !== undefined && other.addressURI !== undefined) { if (!this.addressURI.equals(other.addressURI)) return false; } else { - if (this.addressURI === undefined !== (other.addressURI === undefined)) return false; + if ((this.addressURI === undefined) !== (other.addressURI === undefined)) return false; } const l = this.path.length; @@ -359,7 +347,7 @@ export class Ref { return true; } - hashCode (): number { + hashCode(): number { let acc = hashCodeOf(definedMap(this.addressURI, u => u.toString())); for (const pe of this.path) { acc = addHashCode(acc, pe.kind); @@ -384,16 +372,16 @@ class Location { public readonly virtualRef: Ref; - constructor ( + constructor( canonicalRef: Ref, virtualRef?: Ref, - readonly haveID: boolean = false, + readonly haveID: boolean = false ) { this.canonicalRef = canonicalRef; this.virtualRef = virtualRef !== undefined ? virtualRef : canonicalRef; } - updateWithID (id: any) { + updateWithID(id: any) { if (typeof id !== "string") return this; const parsed = Ref.parse(id); const virtual = this.haveID ? parsed.resolveAgainst(this.virtualRef) : parsed; @@ -404,19 +392,19 @@ class Location { return new Location(this.canonicalRef, virtual, true); } - push (...keys: string[]): Location { + push(...keys: string[]): Location { return new Location(this.canonicalRef.push(...keys), this.virtualRef.push(...keys), this.haveID); } - pushObject (): Location { + pushObject(): Location { return new Location(this.canonicalRef.pushObject(), this.virtualRef.pushObject(), this.haveID); } - pushType (index: number): Location { + pushType(index: number): Location { return new Location(this.canonicalRef.pushType(index), this.virtualRef.pushType(index), this.haveID); } - toString (): string { + toString(): string { return `${this.virtualRef.toString()} (${this.canonicalRef.toString()})`; } } @@ -426,9 +414,9 @@ class Canonizer { private readonly _schemaAddressesAdded = new Set(); - constructor (private readonly _ctx: RunContext) {} + constructor(private readonly _ctx: RunContext) {} - private addIDs (schema: any, loc: Location) { + private addIDs(schema: any, loc: Location) { if (schema === null) return; if (Array.isArray(schema)) { for (let i = 0; i < schema.length; i++) { @@ -461,7 +449,7 @@ class Canonizer { } } - addSchema (schema: any, address: string): boolean { + addSchema(schema: any, address: string): boolean { if (this._schemaAddressesAdded.has(address)) return false; this.addIDs(schema, new Location(Ref.root(address), Ref.root(undefined))); @@ -470,7 +458,7 @@ class Canonizer { } // Returns: Canonical ref - canonize (base: Location, ref: Ref): Location { + canonize(base: Location, ref: Ref): Location { const virtual = ref.resolveAgainst(base.virtualRef); const loc = this._map.get(virtual); if (loc !== undefined) { @@ -483,7 +471,7 @@ class Canonizer { } } -function checkTypeList (typeOrTypes: any, loc: Location): ReadonlySet { +function checkTypeList(typeOrTypes: any, loc: Location): ReadonlySet { let set: Set; if (typeof typeOrTypes === "string") { set = new Set([typeOrTypes]); @@ -512,7 +500,7 @@ function checkTypeList (typeOrTypes: any, loc: Location): ReadonlySet { return set; } -function checkRequiredArray (arr: any, loc: Location): string[] { +function checkRequiredArray(arr: any, loc: Location): string[] { if (!Array.isArray(arr)) { return messageError("SchemaRequiredMustBeStringOrStringArray", withRef(loc, { actual: arr })); } @@ -533,7 +521,7 @@ export const schemaTypeDict = { integer: true, number: true, array: true, - object: true, + object: true }; export type JSONSchemaType = keyof typeof schemaTypeDict; @@ -554,16 +542,16 @@ export type JSONSchemaAttributeProducer = ( unionCases: JSONSchema[] | undefined ) => JSONSchemaAttributes | undefined; -function typeKindForJSONSchemaFormat (format: string): TransformedStringTypeKind | undefined { +function typeKindForJSONSchemaFormat(format: string): TransformedStringTypeKind | undefined { const target = iterableFind( transformedStringTypeTargetTypeKindsMap, - ([_, { jsonSchema }]) => jsonSchema === format, + ([_, { jsonSchema }]) => jsonSchema === format ); if (target === undefined) return undefined; return target[0] as TransformedStringTypeKind; } -function schemaFetchError (base: Location | undefined, address: string): never { +function schemaFetchError(base: Location | undefined, address: string): never { if (base === undefined) { return messageError("SchemaFetchErrorTopLevel", { address }); } else { @@ -572,16 +560,16 @@ function schemaFetchError (base: Location | undefined, address: string): never { } class Resolver { - constructor ( + constructor( private readonly _ctx: RunContext, private readonly _store: JSONSchemaStore, - private readonly _canonizer: Canonizer, + private readonly _canonizer: Canonizer ) {} - private async tryResolveVirtualRef ( + private async tryResolveVirtualRef( fetchBase: Location, lookupBase: Location, - virtualRef: Ref, + virtualRef: Ref ): Promise<[JSONSchema | undefined, Location]> { let didAdd = false; // If we are resolving into a schema file that we haven't seen yet then @@ -611,7 +599,7 @@ class Resolver { lookupLoc = new Location( new Ref(loc.canonicalRef.addressURI, lookupLoc.canonicalRef.path), lookupLoc.virtualRef, - lookupLoc.haveID, + lookupLoc.haveID ); } @@ -620,7 +608,7 @@ class Resolver { } } - async resolveVirtualRef (base: Location, virtualRef: Ref): Promise<[JSONSchema, Location]> { + async resolveVirtualRef(base: Location, virtualRef: Ref): Promise<[JSONSchema, Location]> { if (this._ctx.debugPrintSchemaResolving) { console.log(`resolving ${virtualRef.toString()} relative to ${base.toString()}`); } @@ -640,7 +628,7 @@ class Resolver { const altBase = new Location( base.canonicalRef, new Ref(base.canonicalRef.addressURI, base.virtualRef.path), - base.haveID, + base.haveID ); result = await this.tryResolveVirtualRef(altBase, base, virtualRef); schema = result[0]; @@ -655,20 +643,20 @@ class Resolver { return schemaFetchError(base, virtualRef.address); } - async resolveTopLevelRef (ref: Ref): Promise<[JSONSchema, Location]> { + async resolveTopLevelRef(ref: Ref): Promise<[JSONSchema, Location]> { return await this.resolveVirtualRef(new Location(new Ref(ref.addressURI, [])), new Ref(undefined, ref.path)); } } -async function addTypesInSchema ( +async function addTypesInSchema( resolver: Resolver, typeBuilder: TypeBuilder, references: ReadonlyMap, - attributeProducers: JSONSchemaAttributeProducer[], + attributeProducers: JSONSchemaAttributeProducer[] ): Promise { let typeForCanonicalRef = new EqualityMap(); - function setTypeForLocation (loc: Location, t: TypeRef): void { + function setTypeForLocation(loc: Location, t: TypeRef): void { const maybeRef = typeForCanonicalRef.get(loc.canonicalRef); if (maybeRef !== undefined) { assert(maybeRef === t, "Trying to set path again to different type"); @@ -677,13 +665,13 @@ async function addTypesInSchema ( typeForCanonicalRef.set(loc.canonicalRef, t); } - async function makeObject ( + async function makeObject( loc: Location, attributes: TypeAttributes, properties: StringMap, requiredArray: string[], additionalProperties: any, - sortKey: (k: string) => number | string = (k: string) => k.toLowerCase(), + sortKey: (k: string) => number | string = (k: string) => k.toLowerCase() ): Promise { const required = new Set(requiredArray); const propertiesMap = mapSortBy(mapFromObject(properties), (_, k) => sortKey(k)); @@ -692,7 +680,7 @@ async function addTypesInSchema ( const t = await toType( checkJSONSchema(propSchema, propLoc.canonicalRef), propLoc, - makeNamesTypeAttributes(propName, true), + makeNamesTypeAttributes(propName, true) ); const isOptional = !required.has(propName); return typeBuilder.makeClassProperty(t, isOptional); @@ -707,7 +695,7 @@ async function addTypesInSchema ( additionalPropertiesType = await toType( checkJSONSchema(additionalProperties, additionalLoc.canonicalRef), additionalLoc, - singularizeTypeNames(attributes), + singularizeTypeNames(attributes) ); } @@ -719,7 +707,7 @@ async function addTypesInSchema ( } const additionalProps = mapFromIterable(additionalRequired, _name => - typeBuilder.makeClassProperty(t, false), + typeBuilder.makeClassProperty(t, false) ); mapMergeInto(props, additionalProps); } @@ -727,12 +715,12 @@ async function addTypesInSchema ( return typeBuilder.getUniqueObjectType(attributes, props, additionalPropertiesType); } - async function convertToType (schema: StringMap, loc: Location, typeAttributes: TypeAttributes): Promise { + async function convertToType(schema: StringMap, loc: Location, typeAttributes: TypeAttributes): Promise { const enumArray = Array.isArray(schema.enum) ? schema.enum : undefined; const isConst = schema.const !== undefined; const typeSet = definedMap(schema.type, t => checkTypeList(t, loc)); - function isTypeIncluded (name: JSONSchemaType): boolean { + function isTypeIncluded(name: JSONSchemaType): boolean { if (typeSet !== undefined && !typeSet.has(name)) { return false; } @@ -764,9 +752,9 @@ async function addTypesInSchema ( const includedTypes = setFilter(schemaTypes, isTypeIncluded); let producedAttributesForNoCases: JSONSchemaAttributes[] | undefined = undefined; - function forEachProducedAttribute ( + function forEachProducedAttribute( cases: JSONSchema[] | undefined, - f: (attributes: JSONSchemaAttributes) => void, + f: (attributes: JSONSchemaAttributes) => void ): void { let attributes: JSONSchemaAttributes[]; if (cases === undefined && producedAttributesForNoCases !== undefined) { @@ -789,8 +777,8 @@ async function addTypesInSchema ( } } - function combineProducedAttributes ( - f: (attributes: JSONSchemaAttributes) => TypeAttributes | undefined, + function combineProducedAttributes( + f: (attributes: JSONSchemaAttributes) => TypeAttributes | undefined ): TypeAttributes { let result = emptyTypeAttributes; forEachProducedAttribute(undefined, attr => { @@ -801,7 +789,7 @@ async function addTypesInSchema ( return result; } - function makeAttributes (attributes: TypeAttributes): TypeAttributes { + function makeAttributes(attributes: TypeAttributes): TypeAttributes { if (schema.oneOf === undefined) { attributes = combineTypeAttributes( "union", @@ -809,10 +797,10 @@ async function addTypesInSchema ( combineProducedAttributes(({ forType, forUnion, forCases }) => { assert( forUnion === undefined && forCases === undefined, - "We can't have attributes for unions and cases if we don't have a union", + "We can't have attributes for unions and cases if we don't have a union" ); return forType; - }), + }) ); } @@ -838,7 +826,7 @@ async function addTypesInSchema ( typeAttributes = makeAttributes(typeAttributes); const inferredAttributes = makeTypeAttributesInferred(typeAttributes); - function makeStringType (attributes: TypeAttributes): TypeRef { + function makeStringType(attributes: TypeAttributes): TypeRef { const kind = typeKindForJSONSchemaFormat(schema.format); if (kind === undefined) { return typeBuilder.getStringType(attributes, StringTypes.unrestricted); @@ -847,7 +835,7 @@ async function addTypesInSchema ( } } - async function makeArrayType (): Promise { + async function makeArrayType(): Promise { const singularAttributes = singularizeTypeNames(typeAttributes); const items = schema.items; let itemType: TypeRef; @@ -871,7 +859,7 @@ async function addTypesInSchema ( return typeBuilder.getArrayType(emptyTypeAttributes, itemType); } - async function makeObjectType (): Promise { + async function makeObjectType(): Promise { let required: string[]; if (schema.required === undefined || typeof schema.required === "boolean") { required = []; @@ -907,7 +895,7 @@ async function addTypesInSchema ( const objectAttributes = combineTypeAttributes( "union", inferredAttributes, - combineProducedAttributes(({ forObject }) => forObject), + combineProducedAttributes(({ forObject }) => forObject) ); const order = schema.quicktypePropertyOrder ? schema.quicktypePropertyOrder : []; const orderKey = (propertyName: string) => { @@ -920,7 +908,7 @@ async function addTypesInSchema ( return await makeObject(loc, objectAttributes, properties, required, additionalProperties, orderKey); } - async function makeTypesFromCases (cases: any, kind: string): Promise { + async function makeTypesFromCases(cases: any, kind: string): Promise { const kindLoc = loc.push(kind); if (!Array.isArray(cases)) { return messageError("SchemaSetOperationCasesIsNotArray", withRef(kindLoc, { operation: kind, cases })); @@ -932,7 +920,7 @@ async function addTypesInSchema ( return await toType( checkJSONSchema(t, caseLoc.canonicalRef), caseLoc, - makeTypeAttributesInferred(typeAttributes), + makeTypeAttributesInferred(typeAttributes) ); }); } @@ -940,7 +928,7 @@ async function addTypesInSchema ( const intersectionType = typeBuilder.getUniqueIntersectionType(typeAttributes, undefined); setTypeForLocation(loc, intersectionType); - async function convertOneOrAnyOf (cases: any, kind: string): Promise { + async function convertOneOrAnyOf(cases: any, kind: string): Promise { const typeRefs = await makeTypesFromCases(cases, kind); let unionAttributes = makeTypeAttributesInferred(typeAttributes); if (kind === "oneOf") { @@ -956,7 +944,7 @@ async function addTypesInSchema ( if (forCases !== undefined) { assert( forCases.length === typeRefs.length, - "Number of case attributes doesn't match number of cases", + "Number of case attributes doesn't match number of cases" ); for (let i = 0; i < typeRefs.length; i++) { typeBuilder.addAttributes(typeRefs[i], forCases[i]); @@ -996,7 +984,7 @@ async function addTypesInSchema ( ["null", "null"], ["number", "double"], ["integer", "integer"], - ["boolean", "bool"], + ["boolean", "bool"] ] as Array<[JSONSchemaType, PrimitiveTypeKind]>) { if (!includedTypes.has(name)) continue; @@ -1007,7 +995,7 @@ async function addTypesInSchema ( const stringAttributes = combineTypeAttributes( "union", inferredAttributes, - combineProducedAttributes(({ forString }) => forString), + combineProducedAttributes(({ forString }) => forString) ); if (needStringEnum || isConst) { @@ -1045,7 +1033,7 @@ async function addTypesInSchema ( } if (schema.allOf !== undefined) { - types.push(...await makeTypesFromCases(schema.allOf, "allOf")); + types.push(...(await makeTypesFromCases(schema.allOf, "allOf"))); } if (schema.oneOf !== undefined) { @@ -1060,7 +1048,7 @@ async function addTypesInSchema ( return intersectionType; } - async function toType (schema: JSONSchema, loc: Location, typeAttributes: TypeAttributes): Promise { + async function toType(schema: JSONSchema, loc: Location, typeAttributes: TypeAttributes): Promise { const maybeType = typeForCanonicalRef.get(loc.canonicalRef); if (maybeType !== undefined) { return maybeType; @@ -1088,7 +1076,7 @@ async function addTypesInSchema ( } } -function removeExtension (fn: string): string { +function removeExtension(fn: string): string { const lower = fn.toLowerCase(); const extensions = [".json", ".schema"]; for (const ext of extensions) { @@ -1103,7 +1091,7 @@ function removeExtension (fn: string): string { return fn; } -function nameFromURI (uri: URI): string | undefined { +function nameFromURI(uri: URI): string | undefined { const fragment = uri.fragment(); if (fragment !== "") { const components = fragment.split("/"); @@ -1125,10 +1113,10 @@ function nameFromURI (uri: URI): string | undefined { return messageError("DriverCannotInferNameForSchema", { uri: uri.toString() }); } -async function refsInSchemaForURI ( +async function refsInSchemaForURI( resolver: Resolver, uri: URI, - defaultName: string, + defaultName: string ): Promise | [string, Ref]> { const fragment = uri.fragment(); let propertiesAreTypes = fragment.endsWith("/"); @@ -1163,14 +1151,14 @@ async function refsInSchemaForURI ( } class InputJSONSchemaStore extends JSONSchemaStore { - constructor ( + constructor( private readonly _inputs: Map, - private readonly _delegate?: JSONSchemaStore, + private readonly _delegate?: JSONSchemaStore ) { super(); } - async fetch (address: string): Promise { + async fetch(address: string): Promise { const maybeInput = this._inputs.get(address); if (maybeInput !== undefined) { return checkJSONSchema(parseJSON(maybeInput, "JSON Schema", address), () => Ref.root(address)); @@ -1206,10 +1194,10 @@ export class JSONSchemaInput implements Input { private _needIR = false; - constructor ( + constructor( private _schemaStore: JSONSchemaStore | undefined, additionalAttributeProducers: JSONSchemaAttributeProducer[] = [], - private readonly _additionalSchemaAddresses: readonly string[] = [], + private readonly _additionalSchemaAddresses: readonly string[] = [] ) { this._attributeProducers = [ descriptionAttributeProducer, @@ -1218,19 +1206,19 @@ export class JSONSchemaInput implements Input { uriSchemaAttributesProducer, minMaxAttributeProducer, minMaxLengthAttributeProducer, - patternAttributeProducer, + patternAttributeProducer ].concat(additionalAttributeProducers); } - get needIR (): boolean { + get needIR(): boolean { return this._needIR; } - addTopLevel (name: string, ref: Ref): void { + addTopLevel(name: string, ref: Ref): void { this._topLevels.set(name, ref); } - async addTypes (ctx: RunContext, typeBuilder: TypeBuilder): Promise { + async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise { if (this._schemaSources.length === 0) return; let maybeSchemaStore = this._schemaStore; @@ -1279,15 +1267,15 @@ export class JSONSchemaInput implements Input { await addTypesInSchema(resolver, typeBuilder, this._topLevels, this._attributeProducers); } - addTypesSync (): void { + addTypesSync(): void { return panic("addTypesSync not supported in JSONSchemaInput"); } - async addSource (schemaSource: JSONSchemaSourceData): Promise { + async addSource(schemaSource: JSONSchemaSourceData): Promise { this.addSourceSync(schemaSource); } - addSourceSync (schemaSource: JSONSchemaSourceData): void { + addSourceSync(schemaSource: JSONSchemaSourceData): void { const { name, uris, schema, isConverted } = schemaSource; if (isConverted !== true) { @@ -1335,7 +1323,7 @@ export class JSONSchemaInput implements Input { } } - singleStringSchemaSource (): string | undefined { + singleStringSchemaSource(): string | undefined { if (!this._schemaSources.every(([_, { schema }]) => typeof schema === "string")) { return undefined; } diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index c103d3ffe..96556fe3e 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -23,20 +23,19 @@ /* Imports */ import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type TypeKind} from "../Type"; +import { type Type, type TypeKind } from "../Type"; import { ClassType, ArrayType, MapType, EnumType, UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type NameStyle, type Name, type Namer} from "../Naming"; +import { type NameStyle, type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { type Sourcelike } from "../Source"; -import { - type NamingStyle} from "../support/Strings"; +import { type NamingStyle } from "../support/Strings"; import { allUpperWordStyle, legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit, - makeNameStyle, + makeNameStyle } from "../support/Strings"; import { defined, assertNever, panic, numberEnumValues } from "../support/Support"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; @@ -63,10 +62,10 @@ export const cJSONOptions = { "Source code generation type, whether to generate single or multiple source files", [ ["single-source", true], - ["multi-source", false], + ["multi-source", false] ], "single-source", - "secondary", + "secondary" ), typeIntegerSize: new EnumOption( "integer-size", @@ -75,36 +74,36 @@ export const cJSONOptions = { ["int8_t", "int8_t"], ["int16_t", "int16_t"], ["int32_t", "int32_t"], - ["int64_t", "int64_t"], + ["int64_t", "int64_t"] ], "int64_t", - "secondary", + "secondary" ), hashtableSize: new StringOption( "hashtable-size", "Hashtable size, used when maps are created (64 by default)", "SIZE", - "64", + "64" ), addTypedefAlias: new EnumOption( "typedef-alias", "Add typedef alias to unions, structs, and enums (no typedef by default)", [ ["no-typedef", false], - ["add-typedef", true], + ["add-typedef", true] ], "no-typedef", - "secondary", + "secondary" ), printStyle: new EnumOption( "print-style", "Which cJSON print should be used (formatted by default)", [ ["print-formatted", false], - ["print-unformatted", true], + ["print-unformatted", true] ], "print-formatted", - "secondary", + "secondary" ), typeNamingStyle: new EnumOption("type-style", "Naming style for types", [ pascalValue, @@ -112,7 +111,7 @@ export const cJSONOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue, + camelUpperAcronymsValue ]), memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ underscoreValue, @@ -120,7 +119,7 @@ export const cJSONOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue, + camelUpperAcronymsValue ]), enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ upperUnderscoreValue, @@ -128,8 +127,8 @@ export const cJSONOptions = { pascalValue, camelValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue, - ]), + camelUpperAcronymsValue + ]) }; /* cJSON generator target language */ @@ -140,7 +139,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * @params names: names * @param extension: extension of files */ - constructor (displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { + constructor(displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { super(displayName, names, extension); } @@ -148,7 +147,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Return cJSON generator options * @return cJSON generator options array */ - protected getOptions (): Array> { + protected getOptions(): Array> { return [ cJSONOptions.typeSourceStyle, cJSONOptions.typeIntegerSize, @@ -157,7 +156,7 @@ export class CJSONTargetLanguage extends TargetLanguage { cJSONOptions.hashtableSize, cJSONOptions.typeNamingStyle, cJSONOptions.memberNamingStyle, - cJSONOptions.enumeratorNamingStyle, + cJSONOptions.enumeratorNamingStyle ]; } @@ -165,7 +164,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Indicate if language support union with both number types * @return true */ - get supportsUnionsWithBothNumberTypes (): boolean { + get supportsUnionsWithBothNumberTypes(): boolean { return true; } @@ -173,7 +172,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Indicate if language support optional class properties * @return true */ - get supportsOptionalClassProperties (): boolean { + get supportsOptionalClassProperties(): boolean { return true; } @@ -183,7 +182,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * @param untypedOptionValues * @return cJSON renderer */ - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): CJSONRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): CJSONRenderer { return new CJSONRenderer(this, renderContext, getOptionValues(cJSONOptions, untypedOptionValues)); } } @@ -311,25 +310,25 @@ const keywords = [ "String", "StringArray", "StringReference", - "True", + "True" ]; /* Used to build forbidden global names */ export enum GlobalNames { - ClassMemberConstraints, - ClassMemberConstraintException, - ValueTooLowException, - ValueTooHighException, - ValueTooShortException, - ValueTooLongException, - InvalidPatternException, - CheckConstraint + ClassMemberConstraints = 1, + ClassMemberConstraintException = 2, + ValueTooLowException = 3, + ValueTooHighException = 4, + ValueTooShortException = 5, + ValueTooLongException = 6, + InvalidPatternException = 7, + CheckConstraint = 8 } /* To be able to support circles in multiple files - e.g. class#A using class#B using class#A (obviously not directly) we can forward declare them */ export enum IncludeKind { - ForwardDeclare, - Include + ForwardDeclare = "ForwardDeclare", + Include = "Include" } /* Used to map includes */ @@ -388,10 +387,10 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param renderContext: render context * @param _options: renderer options */ - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); this.typeIntegerSize = _options.typeIntegerSize; @@ -411,7 +410,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for namespace * @return Forbidden names for namespace */ - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return [...keywords, ...this.forbiddenGlobalNames]; } @@ -419,7 +418,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for enums * @return Forbidden names for enums */ - protected forbiddenForEnumCases (_enumType: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_enumType: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -427,7 +426,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for unions members * @return Forbidden names for unions members */ - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -435,7 +434,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build forbidden names for objects * @return Forbidden names for objects */ - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -443,7 +442,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build types member names * @return types member namer */ - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("types", this.namedTypeNameStyle); } @@ -451,7 +450,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build object properties member names * @return object properties member namer */ - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return funPrefixNamer("members", this.memberNameStyle); } @@ -459,7 +458,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build union member names * @return union member namer */ - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return funPrefixNamer("members", this.memberNameStyle); } @@ -467,7 +466,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Build enum member names * @return enum member namer */ - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("enumerators", makeNameStyle(this.enumeratorNamingStyle, legalizeName)); } @@ -479,11 +478,11 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param lookup: Lookup function * @return Proposed union member name */ - protected proposeUnionMemberName ( + protected proposeUnionMemberName( unionType: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string, + lookup: (n: Name) => string ): string { let fieldName = super.proposeUnionMemberName(unionType, unionName, fieldType, lookup); if ("bool" === fieldName) { @@ -500,7 +499,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param fieldType: the variable type * @param fieldName: name of the variable */ - protected emitTypdefAlias (fieldType: Type, fieldName: Name) { + protected emitTypdefAlias(fieldType: Type, fieldName: Name) { if (this._options.addTypedefAlias) { this.emitLine("typedef ", this.quicktypeTypeToCJSON(fieldType, false).cType, " ", fieldName, ";"); this.ensureBlankLine(); @@ -511,7 +510,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create header file(s) * @param proposedFilename: source filename provided from stdin */ - protected emitSourceStructure (proposedFilename: string): void { + protected emitSourceStructure(proposedFilename: string): void { /* Depending of source style option, generate a unique header or multiple header files */ if (this._options.typeSourceStyle) { this.emitSingleSourceStructure(proposedFilename); @@ -524,7 +523,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create a single header file with types and generators * @param proposedFilename: source filename provided from stdin */ - protected emitSingleSourceStructure (proposedFilename: string): void { + protected emitSingleSourceStructure(proposedFilename: string): void { /* Create file */ this.startFile(proposedFilename); @@ -552,12 +551,12 @@ export class CJSONRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevelTypedef(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined, + type => this.namedTypeToNameForTopLevel(type) === undefined ); /* Create enum prototypes */ this.forEachEnum("leading-and-interposing", (enumType: EnumType, _enumName: Name) => - this.emitEnumPrototypes(enumType), + this.emitEnumPrototypes(enumType) ); /* Create union prototypes */ @@ -565,19 +564,19 @@ export class CJSONRenderer extends ConvenienceRenderer { /* Create class prototypes */ this.forEachObject("leading-and-interposing", (classType: ClassType, _className: Name) => - this.emitClassPrototypes(classType), + this.emitClassPrototypes(classType) ); /* Create top level prototypes */ this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevelPrototypes(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined, + type => this.namedTypeToNameForTopLevel(type) === undefined ); /* Create enum functions */ this.forEachEnum("leading-and-interposing", (enumType: EnumType, _enumName: Name) => - this.emitEnumFunctions(enumType), + this.emitEnumFunctions(enumType) ); /* Create union functions */ @@ -585,14 +584,14 @@ export class CJSONRenderer extends ConvenienceRenderer { /* Create class functions */ this.forEachObject("leading-and-interposing", (classType: ClassType, _className: Name) => - this.emitClassFunctions(classType), + this.emitClassFunctions(classType) ); /* Create top level functions */ this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevelFunctions(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined, + type => this.namedTypeToNameForTopLevel(type) === undefined ); /* Close file */ @@ -602,7 +601,7 @@ export class CJSONRenderer extends ConvenienceRenderer { /** * Function called to create a multiple header files with types and generators */ - protected emitMultiSourceStructure (): void { + protected emitMultiSourceStructure(): void { /* Array of includes */ let includes: string[]; @@ -617,14 +616,14 @@ export class CJSONRenderer extends ConvenienceRenderer { }, (unionType, _name) => { this.emitUnion(unionType, includes); - }, + } ); /* Create top level file */ this.forEachTopLevel( "leading", (type: Type, className: Name) => this.emitTopLevel(type, className, includes), - type => this.namedTypeToNameForTopLevel(type) === undefined, + type => this.namedTypeToNameForTopLevel(type) === undefined ); } @@ -633,7 +632,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param enumType: enum type * @param includes: Array of includes */ - protected emitEnum (enumType: EnumType, includes: string[]): void { + protected emitEnum(enumType: EnumType, includes: string[]): void { /* Create file */ const enumName = this.nameForNamedType(enumType); const filename = this.sourcelikeToString(enumName).concat(".h"); @@ -660,7 +659,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create enum typedef * @param enumType: enum type */ - protected emitEnumTypedef (enumType: EnumType): void { + protected emitEnumTypedef(enumType: EnumType): void { /* FIXME: Now there is a language with need of global enum name, see FIXME in makeNameForEnumCase of ConvenienceRenderer.ts, should simplify here when fixed */ const enumName = this.nameForNamedType(enumType); @@ -685,7 +684,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }, "", - true, + true ); this.ensureBlankLine(); this.emitTypdefAlias(enumType, enumName); @@ -695,7 +694,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create enum prototypes * @param enumType: enum type */ - protected emitEnumPrototypes (enumType: EnumType): void { + protected emitEnumPrototypes(enumType: EnumType): void { const enumName = this.nameForNamedType(enumType); this.emitLine("enum ", enumName, " cJSON_Get", enumName, "Value(", this.withConst("cJSON"), " * j);"); @@ -707,7 +706,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create enum functions * @param enumType: enum type */ - protected emitEnumFunctions (enumType: EnumType): void { + protected emitEnumFunctions(enumType: EnumType): void { const enumName = this.nameForNamedType(enumType); /* Create cJSON to enumName generator function */ @@ -719,13 +718,13 @@ export class CJSONRenderer extends ConvenienceRenderer { this.forEachEnumCase(enumType, "none", (name, jsonName) => { this.emitLine( onFirst ? "" : "else ", - "if (!strcmp(cJSON_GetStringValue(j), \"", + 'if (!strcmp(cJSON_GetStringValue(j), "', jsonName, - "\")) x = ", + '")) x = ', combinedName, "_", name, - ";", + ";" ); onFirst = false; }); @@ -745,9 +744,9 @@ export class CJSONRenderer extends ConvenienceRenderer { combinedName, "_", name, - ": j = cJSON_CreateString(\"", + ': j = cJSON_CreateString("', jsonName, - "\"); break;", + '"); break;' ); }); }); @@ -761,7 +760,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param unionType: union type * @param includes: Array of includes */ - protected emitUnion (unionType: UnionType, includes: string[]): void { + protected emitUnion(unionType: UnionType, includes: string[]): void { /* Create file */ const unionName = this.nameForNamedType(unionType); const filename = this.sourcelikeToString(unionName).concat(".h"); @@ -788,7 +787,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create union typedef * @param unionType: union type */ - protected emitUnionTypedef (unionType: UnionType): void { + protected emitUnionTypedef(unionType: UnionType): void { const [_hasNull, nonNulls] = removeNullFromUnion(unionType); const unionName = this.nameForNamedType(unionType); @@ -808,16 +807,16 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.optionalQualifier, " ", this.nameForUnionMember(unionType, type), - ";", + ";" ); } }, "value", - true, + true ); }, "", - true, + true ); this.ensureBlankLine(); this.emitTypdefAlias(unionType, unionName); @@ -827,7 +826,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create union prototypes * @param unionType: union type */ - protected emitUnionPrototypes (unionType: UnionType): void { + protected emitUnionPrototypes(unionType: UnionType): void { const unionName = this.nameForNamedType(unionType); this.emitLine("struct ", unionName, " * cJSON_Get", unionName, "Value(const cJSON * j);"); @@ -840,7 +839,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create union functions * @param unionType: union type */ - protected emitUnionFunctions (unionType: UnionType): void { + protected emitUnionFunctions(unionType: UnionType): void { const [hasNull, nonNulls] = removeNullFromUnion(unionType); const unionName = this.nameForNamedType(unionType); @@ -873,7 +872,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", level > 0 ? level.toString() : "", - ")", + ")" ], () => { const add = (cJSON: TypeCJSON, level: number, child_level: number) => { @@ -892,7 +891,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -904,7 +903,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -919,7 +918,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { this.emitLine( @@ -928,7 +927,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));", + "));" ); this.emitBlock( ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], @@ -940,7 +939,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");", + ");" ); this.emitLine( "list_add_tail(x", @@ -949,9 +948,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));", + " *));" ); - }, + } ); } }; @@ -961,26 +960,26 @@ export class CJSONRenderer extends ConvenienceRenderer { ["if (!cJSON_IsNull(e", child_level.toString(), "))"], () => { add(cJSON, level, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( "list_add_tail(x", child_level.toString(), - ", (void *)0xDEADBEEF, sizeof(void *));", + ", (void *)0xDEADBEEF, sizeof(void *));" ); }); } else { add(cJSON, level, child_level); } - }, + } ); this.emitLine( "x->value.", this.nameForUnionMember(unionType, type), " = x", child_level.toString(), - ";", + ";" ); }); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { @@ -992,7 +991,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = hashtable_create(", this.hashtableSize, - ", false);", + ", false);" ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); @@ -1002,7 +1001,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", level > 0 ? level.toString() : "", - ")", + ")" ], () => { const add = (cJSON: TypeCJSON, level: number, child_level: number) => { @@ -1023,7 +1022,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -1037,7 +1036,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -1054,7 +1053,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { this.emitLine( @@ -1063,7 +1062,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));", + "));" ); this.emitBlock( ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], @@ -1075,7 +1074,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");", + ");" ); this.emitLine( "hashtable_add(x", @@ -1086,9 +1085,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));", + " *));" ); - }, + } ); } }; @@ -1098,7 +1097,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ["if (!cJSON_IsNull(e", child_level.toString(), "))"], () => { add(cJSON, level, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( @@ -1106,20 +1105,20 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", e", child_level.toString(), - "->string, (void *)0xDEADBEEF, sizeof(void *));", + "->string, (void *)0xDEADBEEF, sizeof(void *));" ); }); } else { add(cJSON, level, child_level); } - }, + } ); this.emitLine( "x->value.", this.nameForUnionMember(unionType, type), " = x", child_level.toString(), - ";", + ";" ); }); } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { @@ -1128,7 +1127,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), " = (", cJSON.cType, - " *)0xDEADBEEF;", + " *)0xDEADBEEF;" ); } else if (cJSON.cjsonType === "cJSON_String") { this.emitLine( @@ -1136,7 +1135,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), " = strdup(", cJSON.getValue, - "(j));", + "(j));" ); } else { this.emitLine( @@ -1144,7 +1143,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), " = ", cJSON.getValue, - "(j);", + "(j);" ); } }); @@ -1182,7 +1181,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = ", cJSON.createObject, - "();", + "();" ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( @@ -1193,7 +1192,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { const add = (cJSON: TypeCJSON, child_level: number) => { @@ -1209,7 +1208,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", ", cJSON.items!.createObject, - "());", + "());" ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -1223,7 +1222,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));", + "));" ); } else { this.emitLine( @@ -1233,7 +1232,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));", + "));" ); } }; @@ -1243,13 +1242,13 @@ export class CJSONRenderer extends ConvenienceRenderer { ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], () => { add(cJSON, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), - ", cJSON_CreateNull());", + ", cJSON_CreateNull());" ); }); } else { @@ -1263,7 +1262,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); }); this.emitLine("j = j", child_level.toString(), ";"); @@ -1276,7 +1275,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = ", cJSON.createObject, - "();", + "();" ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine("char **keys", child_level.toString(), " = NULL;"); @@ -1289,7 +1288,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), ", &keys", child_level.toString(), - ");", + ");" ); this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { this.emitBlock( @@ -1302,7 +1301,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)", + "++)" ], () => { this.emitLine( @@ -1317,7 +1316,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);", + "]);" ); const add = (cJSON: TypeCJSON, child_level: number) => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -1337,7 +1336,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "], ", cJSON.items!.createObject, - "());", + "());" ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -1356,7 +1355,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));", + "));" ); } else { this.emitLine( @@ -1371,7 +1370,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));", + "));" ); } }; @@ -1381,11 +1380,11 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")", + ")" ], () => { add(cJSON, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( @@ -1396,13 +1395,13 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "], cJSON_CreateNull());", + "], cJSON_CreateNull());" ); }); } else { add(cJSON, child_level); } - }, + } ); this.emitLine("cJSON_free(keys", child_level.toString(), ");"); }); @@ -1418,16 +1417,16 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.createObject, "(x->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); } - }, + } ); onFirst = false; } }); this.emitLine("return j;"); - }, + } ); this.ensureBlankLine(); @@ -1447,7 +1446,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ")", + ")" ], () => { this.emitLine( @@ -1458,7 +1457,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -1479,16 +1478,16 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); - }, + } ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); } } @@ -1500,7 +1499,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); }); this.emitLine( @@ -1509,9 +1508,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); - }, + } ); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { const level = 0; @@ -1522,7 +1521,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ")", + ")" ], () => { this.emitLine("char **keys", child_level.toString(), " = NULL;"); @@ -1535,7 +1534,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.nameForUnionMember(unionType, type), ", &keys", child_level.toString(), - ");", + ");" ); this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { this.emitBlock( @@ -1548,7 +1547,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)", + "++)" ], () => { this.emitLine( @@ -1563,7 +1562,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);", + "]);" ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -1581,28 +1580,28 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")", + ")" ], () => { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); - }, + } ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); } } }); - }, + } ); this.emitLine("cJSON_free(keys", child_level.toString(), ");"); }); @@ -1612,9 +1611,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); - }, + } ); } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { /* Nothing to do */ @@ -1627,7 +1626,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.deleteType, "(x->value.", this.nameForUnionMember(unionType, type), - ");", + ");" ); } else { /* Nothing to do */ @@ -1647,7 +1646,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param classType: class type * @param includes: Array of includes */ - protected emitClass (classType: ClassType, includes: string[]): void { + protected emitClass(classType: ClassType, includes: string[]): void { /* Create file */ const className = this.nameForNamedType(classType); const filename = this.sourcelikeToString(className).concat(".h"); @@ -1674,7 +1673,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create class typedef * @param classType: class type */ - protected emitClassTypedef (classType: ClassType): void { + protected emitClassTypedef(classType: ClassType): void { const className = this.nameForNamedType(classType); this.emitDescription(this.descriptionForType(classType)); @@ -1690,12 +1689,12 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.optionalQualifier, " ", name, - ";", + ";" ); }); }, "", - true, + true ); this.ensureBlankLine(); this.emitTypdefAlias(classType, className); @@ -1705,7 +1704,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create class prototypes * @param classType: class type */ - protected emitClassPrototypes (classType: ClassType): void { + protected emitClassPrototypes(classType: ClassType): void { const className = this.nameForNamedType(classType); this.emitLine("struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s);"); @@ -1720,7 +1719,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create class functions * @param classType: class type */ - protected emitClassFunctions (classType: ClassType): void { + protected emitClassFunctions(classType: ClassType): void { const className = this.nameForNamedType(classType); /* Create string to className generator function */ @@ -1736,7 +1735,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - }, + } ); this.ensureBlankLine(); @@ -1768,7 +1767,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level2.toString(), ", sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if (cJSON.cjsonType === "cJSON_Map") { /* Not supported */ @@ -1783,7 +1782,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.cType, " *)0xDEADBEEF, sizeof(", cJSON.cType, - " *));", + " *));" ); } else if (cJSON.cjsonType === "cJSON_String") { this.emitLine( @@ -1795,7 +1794,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.cType, - " *));", + " *));" ); } else if ( cJSON.cjsonType === "cJSON_Object" || @@ -1810,7 +1809,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.cType, - " *));", + " *));" ); } else { this.emitLine( @@ -1819,7 +1818,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.cType, - "));", + "));" ); this.emitBlock( ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], @@ -1831,7 +1830,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(e", child_level.toString(), - ");", + ");" ); this.emitLine( "list_add_tail(x", @@ -1840,12 +1839,12 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.cType, - " *));", + " *));" ); - }, + } ); } - }, + } ); }); } else if (type instanceof ClassType) { @@ -1854,23 +1853,23 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock( !cJSON.isNullable ? [ - "if (cJSON_HasObjectItem(j", - level > 0 ? level.toString() : "", - ", \"", - jsonName, - "\"))", - ] + "if (cJSON_HasObjectItem(j", + level > 0 ? level.toString() : "", + ', "', + jsonName, + '"))' + ] : [ - "if ((cJSON_HasObjectItem(j", - level > 0 ? level.toString() : "", - ", \"", - jsonName, - "\")) && (!cJSON_IsNull(cJSON_GetObjectItemCaseSensitive(j", - level > 0 ? level.toString() : "", - ", \"", - jsonName, - "\"))))", - ], + "if ((cJSON_HasObjectItem(j", + level > 0 ? level.toString() : "", + ', "', + jsonName, + '")) && (!cJSON_IsNull(cJSON_GetObjectItemCaseSensitive(j', + level > 0 ? level.toString() : "", + ', "', + jsonName, + '"))))' + ], () => { if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { const child_level = level + 1; @@ -1878,7 +1877,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.cType, " * x", child_level.toString(), - " = list_create(false, NULL);", + " = list_create(false, NULL);" ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); @@ -1887,9 +1886,9 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\");", + '");' ); this.emitBlock( [ @@ -1897,14 +1896,14 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level.toString(), - ")", + ")" ], () => { const add = ( type: Type, cJSON: TypeCJSON, level: number, - child_level: number, + child_level: number ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof ArrayType) { @@ -1917,7 +1916,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level2.toString(), ", sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { panic("Invalid type"); @@ -1935,7 +1934,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -1947,7 +1946,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -1962,7 +1961,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { this.emitLine( @@ -1971,13 +1970,13 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));", + "));" ); this.emitBlock( [ "if (NULL != tmp", level > 0 ? level.toString() : "", - ")", + ")" ], () => { this.emitLine( @@ -1987,7 +1986,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");", + ");" ); this.emitLine( "list_add_tail(x", @@ -1996,9 +1995,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));", + " *));" ); - }, + } ); } }; @@ -2008,23 +2007,23 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if (!cJSON_IsNull(e", child_level.toString(), - "))", + "))" ], () => { add(property.type, cJSON, level, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( "list_add_tail(x", child_level.toString(), - ", (void *)0xDEADBEEF, sizeof(void *));", + ", (void *)0xDEADBEEF, sizeof(void *));" ); }); } else { add(property.type, cJSON, level, child_level); } - }, + } ); this.emitLine( "x", @@ -2033,7 +2032,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = x", child_level.toString(), - ";", + ";" ); }); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { @@ -2044,7 +2043,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = hashtable_create(", this.hashtableSize, - ", false);", + ", false);" ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); @@ -2053,9 +2052,9 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\");", + '");' ); this.emitBlock( [ @@ -2063,14 +2062,14 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level.toString(), - ")", + ")" ], () => { const add = ( type: Type, cJSON: TypeCJSON, level: number, - child_level: number, + child_level: number ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof MapType) { @@ -2085,7 +2084,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level2.toString(), ", sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { panic("Invalid type"); @@ -2105,7 +2104,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -2119,7 +2118,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ")), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if ( cJSON.items!.cjsonType === "cJSON_Object" || @@ -2136,7 +2135,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { this.emitLine( @@ -2145,13 +2144,13 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", cJSON.items!.cType, - "));", + "));" ); this.emitBlock( [ "if (NULL != tmp", level > 0 ? level.toString() : "", - ")", + ")" ], () => { this.emitLine( @@ -2161,7 +2160,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e", child_level.toString(), - ");", + ");" ); this.emitLine( "hashtable_add(x", @@ -2172,9 +2171,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", ", sizeof(", cJSON.items!.cType, - " *));", + " *));" ); - }, + } ); } }; @@ -2184,11 +2183,11 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if (!cJSON_IsNull(e", child_level.toString(), - "))", + "))" ], () => { add(property.type, cJSON, level, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( @@ -2196,13 +2195,13 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", e", child_level.toString(), - "->string, (void *)0xDEADBEEF, sizeof(void *));", + "->string, (void *)0xDEADBEEF, sizeof(void *));" ); }); } else { add(property.type, cJSON, level, child_level); } - }, + } ); this.emitLine( "x", @@ -2211,7 +2210,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = x", child_level.toString(), - ";", + ";" ); }); } else if ( @@ -2225,7 +2224,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = (", cJSON.cType, - " *)0xDEADBEEF;", + " *)0xDEADBEEF;" ); } else if (cJSON.cjsonType === "cJSON_String") { this.emitLine( @@ -2237,9 +2236,9 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\")));", + '")));' ); } else if ( cJSON.cjsonType === "cJSON_Object" || @@ -2254,9 +2253,9 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\"));", + '"));' ); } else { if (property.isOptional || cJSON.isNullable) { @@ -2268,7 +2267,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = cJSON_malloc(sizeof(", cJSON.cType, - "))))", + "))))" ], () => { this.emitLine( @@ -2280,11 +2279,11 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\"));", + '"));' ); - }, + } ); } else { this.emitLine( @@ -2296,13 +2295,13 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\"));", + '"));' ); } } - }, + } ); if (!property.isOptional && !cJSON.isNullable) { if (cJSON.cjsonType === "cJSON_Array") { @@ -2312,7 +2311,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - " = list_create(false, NULL);", + " = list_create(false, NULL);" ); }); } else if (cJSON.cjsonType === "cJSON_Map") { @@ -2324,7 +2323,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = hashtable_create(", this.hashtableSize, - ", false);", + ", false);" ); }); } else if ( @@ -2339,7 +2338,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = (", cJSON.cType, - " *)0xDEADBEEF;", + " *)0xDEADBEEF;" ); }); } else if (cJSON.cjsonType === "cJSON_String") { @@ -2352,7 +2351,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, " = cJSON_malloc(sizeof(", cJSON.cType, - "))))", + "))))" ], () => { this.emitLine( @@ -2360,9 +2359,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - "[0] = '\\0';", + "[0] = '\\0';" ); - }, + } ); }); } else { @@ -2377,7 +2376,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - }, + } ); this.ensureBlankLine(); @@ -2400,7 +2399,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = list_get_head(x", level.toString(), - ");", + ");" ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.cjsonType === "cJSON_Array") { @@ -2411,7 +2410,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level2.toString(), - ");", + ");" ); } else if (cJSON.cjsonType === "cJSON_Map") { /* Not supported */ @@ -2423,7 +2422,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", ", cJSON.createObject, - "());", + "());" ); } else if ( cJSON.cjsonType === "cJSON_String" || @@ -2437,7 +2436,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.createObject, "(x", child_level.toString(), - "));", + "));" ); } else { this.emitLine( @@ -2447,7 +2446,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.createObject, "(*x", child_level.toString(), - "));", + "));" ); } @@ -2456,7 +2455,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = list_get_next(x", level.toString(), - ");", + ");" ); }); }); @@ -2473,9 +2472,9 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = cJSON_AddArrayToObject(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\");", + '");' ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( @@ -2486,7 +2485,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); this.emitBlock( ["while (NULL != x", child_level.toString(), ")"], @@ -2494,7 +2493,7 @@ export class CJSONRenderer extends ConvenienceRenderer { const add = ( type: Type, cJSON: TypeCJSON, - child_level: number, + child_level: number ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof ArrayType) { @@ -2505,7 +2504,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", j", child_level2.toString(), - ");", + ");" ); } else { panic("Invalid type"); @@ -2520,7 +2519,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), ", ", cJSON.items!.createObject, - "());", + "());" ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -2534,7 +2533,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));", + "));" ); } else { this.emitLine( @@ -2544,7 +2543,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));", + "));" ); } }; @@ -2554,17 +2553,17 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")", + ")" ], () => { add(property.type, cJSON, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), - ", cJSON_CreateNull());", + ", cJSON_CreateNull());" ); }); } else { @@ -2578,12 +2577,12 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); - }, + } ); }); - }, + } ); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { const child_level = level + 1; @@ -2595,7 +2594,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = ", cJSON.createObject, - "();", + "();" ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine("char **keys", child_level.toString(), " = NULL;"); @@ -2608,7 +2607,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, ", &keys", child_level.toString(), - ");", + ");" ); this.emitBlock( ["if (NULL != keys", child_level.toString(), ")"], @@ -2623,7 +2622,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)", + "++)" ], () => { this.emitLine( @@ -2638,12 +2637,12 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);", + "]);" ); const add = ( type: Type, cJSON: TypeCJSON, - child_level: number, + child_level: number ) => { if (cJSON.items!.cjsonType === "cJSON_Array") { if (type instanceof MapType) { @@ -2659,7 +2658,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "], j", child_level2.toString(), - ");", + ");" ); } else { panic("Invalid type"); @@ -2685,7 +2684,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "], ", cJSON.items!.createObject, - "());", + "());" ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -2704,7 +2703,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(x", child_level.toString(), - "));", + "));" ); } else { this.emitLine( @@ -2719,7 +2718,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.createObject, "(*x", child_level.toString(), - "));", + "));" ); } }; @@ -2729,11 +2728,11 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")", + ")" ], () => { add(property.type, cJSON, child_level); - }, + } ); this.emitBlock(["else"], () => { this.emitLine( @@ -2744,33 +2743,33 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "], cJSON_CreateNull());", + "], cJSON_CreateNull());" ); }); } else { add(property.type, cJSON, child_level); } - }, + } ); this.emitLine( "cJSON_free(keys", child_level.toString(), - ");", + ");" ); - }, + } ); this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", j", + '", j', child_level.toString(), - ");", + ");" ); }); - }, + } ); } else if (cJSON.cjsonType === "cJSON_Invalid") { /* Nothing to do */ @@ -2783,20 +2782,20 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\");", + '");' ); - }, + } ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\");", + '");' ); } } else if (cJSON.cjsonType === "cJSON_String") { @@ -2807,15 +2806,15 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", x", + '", x', level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); - }, + } ); if (!property.isOptional && !cJSON.isNullable) { this.emitBlock(["else"], () => { @@ -2823,9 +2822,9 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", \"\");", + '", "");' ); }); } @@ -2841,32 +2840,32 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", ", + '", ', cJSON.createObject, "(x", level > 0 ? level.toString() : "", "->", name, - "));", + "));" ); - }, + } ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", ", + '", ', cJSON.createObject, "(x", level > 0 ? level.toString() : "", "->", name, - "));", + "));" ); } } else if (cJSON.cjsonType === "cJSON_Enum") { @@ -2878,32 +2877,32 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", ", + '", ', cJSON.createObject, "(*x", level > 0 ? level.toString() : "", "->", name, - "));", + "));" ); - }, + } ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", ", + '", ', cJSON.createObject, "(x", level > 0 ? level.toString() : "", "->", name, - "));", + "));" ); } } else { @@ -2915,28 +2914,28 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", *x", + '", *x', level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); - }, + } ); } else { this.emitLine( cJSON.addToObject, "(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\", x", + '", x', level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); } } @@ -2946,9 +2945,9 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "cJSON_AddNullToObject(j", level > 0 ? level.toString() : "", - ", \"", + ', "', jsonName, - "\");", + '");' ); }); } @@ -2960,7 +2959,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return j;"); - }, + } ); this.ensureBlankLine(); @@ -2991,7 +2990,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = list_get_head(x", level.toString(), - ");", + ");" ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.cjsonType === "cJSON_Array") { @@ -3023,7 +3022,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -3033,7 +3032,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); } else { panic("Invalid type"); @@ -3054,16 +3053,16 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); - }, + } ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); } } @@ -3075,7 +3074,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); }); this.emitLine( @@ -3084,9 +3083,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); - }, + } ); } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { const child_level = level + 1; @@ -3103,7 +3102,7 @@ export class CJSONRenderer extends ConvenienceRenderer { name, ", &keys", child_level.toString(), - ");", + ");" ); this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { this.emitBlock( @@ -3116,7 +3115,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "; index", child_level.toString(), - "++)", + "++)" ], () => { this.emitLine( @@ -3131,7 +3130,7 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), "[index", child_level.toString(), - "]);", + "]);" ); this.emitBlock( ["if (NULL != x", child_level.toString(), ")"], @@ -3143,7 +3142,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); } else { panic("Invalid type"); @@ -3161,29 +3160,29 @@ export class CJSONRenderer extends ConvenienceRenderer { [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")", + ")" ], () => { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); - }, + } ); } else { this.emitLine( cJSON.items!.deleteType, "(x", child_level.toString(), - ");", + ");" ); } } - }, + } ); - }, + } ); this.emitLine("cJSON_free(keys", child_level.toString(), ");"); }); @@ -3193,9 +3192,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); - }, + } ); } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { /* Nothing to do */ @@ -3213,9 +3212,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); - }, + } ); } else { if (property.isOptional || cJSON.isNullable) { @@ -3228,9 +3227,9 @@ export class CJSONRenderer extends ConvenienceRenderer { level > 0 ? level.toString() : "", "->", name, - ");", + ");" ); - }, + } ); } } @@ -3251,7 +3250,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param className: top level class name * @param includes: Array of includes */ - protected emitTopLevel (type: Type, className: Name, includes: string[]): void { + protected emitTopLevel(type: Type, className: Name, includes: string[]): void { /* Create file */ const filename = this.sourcelikeToString(className).concat(".h"); this.startFile(filename); @@ -3280,7 +3279,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type of the top level element * @param className: top level class name */ - protected emitTopLevelTypedef (type: Type, className: Name): void { + protected emitTopLevelTypedef(type: Type, className: Name): void { this.emitBlock( ["struct ", className], () => { @@ -3289,11 +3288,11 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.cType, cJSON.optionalQualifier !== "" ? " " : "", cJSON.optionalQualifier, - " value;", + " value;" ); }, "", - true, + true ); this.ensureBlankLine(); this.emitTypdefAlias(type, className); @@ -3304,7 +3303,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type of the top level element * @param className: top level class name */ - protected emitTopLevelPrototypes (_type: Type, className: Name): void { + protected emitTopLevelPrototypes(_type: Type, className: Name): void { this.emitLine("struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s);"); this.emitLine("struct ", className, " * cJSON_Get", className, "Value(", this.withConst("cJSON"), " * j);"); this.emitLine("cJSON * cJSON_Create", className, "(", this.withConst(["struct ", className]), " * x);"); @@ -3318,7 +3317,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type of the top level element * @param className: top level class name */ - protected emitTopLevelFunctions (type: Type, className: Name): void { + protected emitTopLevelFunctions(type: Type, className: Name): void { /* Create string to className generator function */ this.emitBlock( ["struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s)"], @@ -3332,7 +3331,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - }, + } ); this.ensureBlankLine(); @@ -3364,7 +3363,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEAF, sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -3372,7 +3371,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e)), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { this.emitLine( @@ -3380,7 +3379,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } }; @@ -3391,7 +3390,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); this.emitBlock(["else"], () => { this.emitLine( - "list_add_tail(x->value, (void *)0xDEADBEEF, sizeof(void *));", + "list_add_tail(x->value, (void *)0xDEADBEEF, sizeof(void *));" ); }); } else { @@ -3418,7 +3417,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.cType, " *)0xDEADBEEF, sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else if (cJSON.items!.cjsonType === "cJSON_String") { this.emitLine( @@ -3426,7 +3425,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e)), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } else { this.emitLine( @@ -3434,7 +3433,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.items!.getValue, "(e), sizeof(", cJSON.items!.cType, - " *));", + " *));" ); } }; @@ -3445,7 +3444,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); this.emitBlock(["else"], () => { this.emitLine( - "hashtable_add(x->value, e->string, (void *)0xDEADBEEF, sizeof(void *));", + "hashtable_add(x->value, e->string, (void *)0xDEADBEEF, sizeof(void *));" ); }); } else { @@ -3465,7 +3464,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - }, + } ); this.ensureBlankLine(); @@ -3493,7 +3492,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "cJSON_AddItemToArray(j, ", cJSON.items!.createObject, - "());", + "());" ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -3503,13 +3502,13 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "cJSON_AddItemToArray(j, ", cJSON.items!.createObject, - "(x1));", + "(x1));" ); } else { this.emitLine( "cJSON_AddItemToArray(j, ", cJSON.items!.createObject, - "(*x1));", + "(*x1));" ); } }; @@ -3539,7 +3538,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["for (size_t index = 0; index < count; index++)"], () => { this.emitLine( cJSON.items!.cType, - " *x2 = hashtable_lookup(x->value, keys[index]);", + " *x2 = hashtable_lookup(x->value, keys[index]);" ); const add = (cJSON: TypeCJSON) => { if (cJSON.items!.cjsonType === "cJSON_Array") { @@ -3553,7 +3552,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j, keys[index], ", cJSON.items!.createObject, - "());", + "());" ); } else if ( cJSON.items!.cjsonType === "cJSON_String" || @@ -3564,14 +3563,14 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.addToObject, "(j, keys[index], ", cJSON.items!.createObject, - "(x2));", + "(x2));" ); } else { this.emitLine( cJSON.addToObject, "(j, keys[index], ", cJSON.items!.createObject, - "(*x2));", + "(*x2));" ); } }; @@ -3583,7 +3582,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["else"], () => { this.emitLine( cJSON.addToObject, - "(j, keys[index], cJSON_CreateNull());", + "(j, keys[index], cJSON_CreateNull());" ); }); } else { @@ -3603,7 +3602,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }); this.emitLine("return j;"); - }, + } ); this.ensureBlankLine(); @@ -3687,7 +3686,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param isNullable: true if the field is nullable * @return cJSON type */ - protected quicktypeTypeToCJSON (t: Type, isOptional: boolean, isNullable = false): TypeCJSON { + protected quicktypeTypeToCJSON(t: Type, isOptional: boolean, isNullable = false): TypeCJSON { /* Compute cJSON type */ return matchType( t, @@ -3702,7 +3701,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "", deleteType: "", items: undefined, - isNullable, + isNullable }; }, _nullType => { @@ -3716,7 +3715,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNull", deleteType: "cJSON_free", items: undefined, - isNullable, + isNullable }; }, _boolType => { @@ -3730,7 +3729,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateBool", deleteType: "cJSON_free", items: undefined, - isNullable, + isNullable }; }, _integerType => { @@ -3744,7 +3743,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNumber", deleteType: "cJSON_free", items: undefined, - isNullable, + isNullable }; }, _doubleType => { @@ -3758,7 +3757,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNumber", deleteType: "cJSON_free", items: undefined, - isNullable, + isNullable }; }, _stringType => { @@ -3772,7 +3771,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateString", deleteType: "cJSON_free", items: undefined, - isNullable, + isNullable }; }, arrayType => { @@ -3787,7 +3786,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateArray", deleteType: "list_release", items, - isNullable, + isNullable }; }, classType => { @@ -3801,7 +3800,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: ["cJSON_Create", this.nameForNamedType(classType)], deleteType: ["cJSON_Delete", this.nameForNamedType(classType)], items: undefined, - isNullable, + isNullable }; }, mapType => { @@ -3816,7 +3815,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateObject", deleteType: "hashtable_release", items, - isNullable, + isNullable }; }, enumType => { @@ -3830,7 +3829,7 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: ["cJSON_Create", this.nameForNamedType(enumType)], deleteType: "cJSON_free", items: undefined, - isNullable, + isNullable }; }, unionType => { @@ -3848,10 +3847,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: ["cJSON_Create", this.nameForNamedType(unionType)], deleteType: ["cJSON_Delete", this.nameForNamedType(unionType)], items: undefined, - isNullable, + isNullable }; } - }, + } ); } @@ -3859,7 +3858,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create a file * @param proposedFilename: source filename provided from stdin */ - protected startFile (proposedFilename: Sourcelike): void { + protected startFile(proposedFilename: Sourcelike): void { /* Check if previous file is closed, create a new file */ assert(this.currentFilename === undefined, "Previous file wasn't finished"); if (proposedFilename !== undefined) { @@ -3877,7 +3876,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "To get json data from cJSON object use the following: struct * data = cJSON_GetValue();", "To get cJSON object from json data use the following: cJSON * cjson = cJSON_Create();", "To print json string from json data use the following: char * string = cJSON_Print();", - "To delete json data use the following: cJSON_Delete();", + "To delete json data use the following: cJSON_Delete();" ]); this.ensureBlankLine(); @@ -3885,18 +3884,18 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "#ifndef __", allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__", + "__" ); this.emitLine( "#define __", allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__", + "__" ); this.ensureBlankLine(); /* Write C++ guard */ this.emitLine("#ifdef __cplusplus"); - this.emitLine("extern \"C\" {"); + this.emitLine('extern "C" {'); this.emitLine("#endif"); this.ensureBlankLine(); @@ -3927,7 +3926,7 @@ export class CJSONRenderer extends ConvenienceRenderer { /** * Function called to close current file */ - protected finishFile (): void { + protected finishFile(): void { /* Check if file has been created */ if (this.currentFilename !== undefined) { /* Write C++ guard */ @@ -3940,7 +3939,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( "#endif /* __", allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__ */", + "__ */" ); this.ensureBlankLine(); @@ -3955,7 +3954,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @note If returning true, canBeForwardDeclared must be declared * @return Always returns true */ - protected get needsTypeDeclarationBeforeUse (): boolean { + protected get needsTypeDeclarationBeforeUse(): boolean { return true; } @@ -3963,7 +3962,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Check if type can be forward declared * @return true for classes, false otherwise */ - protected canBeForwardDeclared (type: Type): boolean { + protected canBeForwardDeclared(type: Type): boolean { return type.kind === "class"; } @@ -3971,7 +3970,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * Add const to wanted Sourcelike * @return Const Sourcelike */ - protected withConst (s: Sourcelike): Sourcelike { + protected withConst(s: Sourcelike): Sourcelike { return ["const ", s]; } @@ -3980,15 +3979,15 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param name: filename to include * @pram global: true if global include, false otherwise (default) */ - protected emitIncludeLine (name: Sourcelike, global = false): void { - this.emitLine("#include ", global ? "<" : "\"", name, global ? ">" : "\""); + protected emitIncludeLine(name: Sourcelike, global = false): void { + this.emitLine("#include ", global ? "<" : '"', name, global ? ">" : '"'); } /** * Emit description block * @param lines: description block lines */ - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } @@ -4000,12 +3999,12 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param withSemicolon: true to add semicolon at the end of the block, false otherwise * @param withIndent: true to indent the block (default), false otherwise */ - protected emitBlock ( + protected emitBlock( line: Sourcelike, f: () => void, withName = "", withSemicolon = false, - withIndent = true, + withIndent = true ): void { this.emitLine(line, " {"); this.preventBlankLine(); @@ -4036,7 +4035,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: class, union or enum type * @param filename: current file name */ - protected emitIncludes (type: ClassType | UnionType | EnumType, filename: string): void { + protected emitIncludes(type: ClassType | UnionType | EnumType, filename: string): void { /* List required includes */ const includes: IncludeMap = new Map(); if (type instanceof UnionType) { @@ -4066,7 +4065,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param includes: include map * @param propertyType: property type */ - protected updateIncludes (isClassMember: boolean, includes: IncludeMap, propertyType: Type): void { + protected updateIncludes(isClassMember: boolean, includes: IncludeMap, propertyType: Type): void { const propTypes = this.generatedTypes(isClassMember, propertyType); for (const t of propTypes) { const typeName = this.sourcelikeToString(t.name); @@ -4116,7 +4115,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param type: type * @return Type record array */ - protected generatedTypes (isClassMember: boolean, type: Type): TypeRecord[] { + protected generatedTypes(isClassMember: boolean, type: Type): TypeRecord[] { const result: TypeRecord[] = []; const recur = (forceInclude: boolean, isVariant: boolean, l: number, t: Type) => { if (t instanceof ArrayType) { @@ -4127,7 +4126,7 @@ export class CJSONRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude, + forceInclude }); } else if (t instanceof MapType) { recur(forceInclude, isVariant, l + 1, t.values); @@ -4137,7 +4136,7 @@ export class CJSONRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude: false, + forceInclude: false }); } else if (t instanceof UnionType) { /** @@ -4161,7 +4160,7 @@ export class CJSONRenderer extends ConvenienceRenderer { type: t, level: l, variant: true, - forceInclude, + forceInclude }); /** intentional "fall-through", add all subtypes as well - but forced include */ } diff --git a/packages/quicktype-core/src/language/CPlusPlus.ts b/packages/quicktype-core/src/language/CPlusPlus.ts index c486c7827..94b60d3a4 100644 --- a/packages/quicktype-core/src/language/CPlusPlus.ts +++ b/packages/quicktype-core/src/language/CPlusPlus.ts @@ -5,26 +5,25 @@ import { iterableFirst, iterableFind, iterableSome, - withDefault, + withDefault } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type TypeKind, type ClassProperty} from "../Type"; +import { type Type, type TypeKind, type ClassProperty } from "../Type"; import { ClassType, ArrayType, MapType, EnumType, UnionType } from "../Type"; import { nullableFromUnion, matchType, removeNullFromUnion, isNamedType, directlyReachableTypes } from "../TypeUtils"; -import { type NameStyle, type Name, type Namer} from "../Naming"; +import { type NameStyle, type Name, type Namer } from "../Naming"; import { funPrefixNamer, DependencyName } from "../Naming"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { - type NamingStyle} from "../support/Strings"; +import { type NamingStyle } from "../support/Strings"; import { legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit, stringEscape, - makeNameStyle, + makeNameStyle } from "../support/Strings"; import { defined, assertNever, panic, numberEnumValues } from "../support/Support"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; @@ -52,47 +51,47 @@ export const cPlusPlusOptions = { "Source code generation type, whether to generate single or multiple source files", [ ["single-source", true], - ["multi-source", false], + ["multi-source", false] ], "single-source", - "secondary", + "secondary" ), includeLocation: new EnumOption( "include-location", "Whether json.hpp is to be located globally or locally", [ ["local-include", true], - ["global-include", false], + ["global-include", false] ], "local-include", - "secondary", + "secondary" ), codeFormat: new EnumOption( "code-format", "Generate classes with getters/setters, instead of structs", [ ["with-struct", false], - ["with-getter-setter", true], + ["with-getter-setter", true] ], - "with-getter-setter", + "with-getter-setter" ), wstring: new EnumOption( "wstring", "Store strings using Utf-16 std::wstring, rather than Utf-8 std::string", [ ["use-string", false], - ["use-wstring", true], + ["use-wstring", true] ], - "use-string", + "use-string" ), westConst: new EnumOption( "const-style", "Put const to the left/west (const T) or right/east (T const)", [ ["west-const", true], - ["east-const", false], + ["east-const", false] ], - "west-const", + "west-const" ), justTypes: new BooleanOption("just-types", "Plain types only", false), namespace: new StringOption("namespace", "Name of the generated namespace(s)", "NAME", "quicktype"), @@ -103,7 +102,7 @@ export const cPlusPlusOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue, + camelUpperAcronymsValue ]), memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ underscoreValue, @@ -111,7 +110,7 @@ export const cPlusPlusOptions = { camelValue, upperUnderscoreValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue, + camelUpperAcronymsValue ]), enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ upperUnderscoreValue, @@ -119,18 +118,18 @@ export const cPlusPlusOptions = { pascalValue, camelValue, pascalUpperAcronymsValue, - camelUpperAcronymsValue, + camelUpperAcronymsValue ]), boost: new BooleanOption("boost", "Require a dependency on boost. Without boost, C++17 is required", true), - hideNullOptional: new BooleanOption("hide-null-optional", "Hide null value for optional field", false), + hideNullOptional: new BooleanOption("hide-null-optional", "Hide null value for optional field", false) }; export class CPlusPlusTargetLanguage extends TargetLanguage { - constructor (displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { + constructor(displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { super(displayName, names, extension); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ cPlusPlusOptions.justTypes, cPlusPlusOptions.namespace, @@ -144,33 +143,33 @@ export class CPlusPlusTargetLanguage extends TargetLanguage { cPlusPlusOptions.enumeratorNamingStyle, cPlusPlusOptions.enumType, cPlusPlusOptions.boost, - cPlusPlusOptions.hideNullOptional, + cPlusPlusOptions.hideNullOptional ]; } - get supportsUnionsWithBothNumberTypes (): boolean { + get supportsUnionsWithBothNumberTypes(): boolean { return true; } - get supportsOptionalClassProperties (): boolean { + get supportsOptionalClassProperties(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): CPlusPlusRenderer { return new CPlusPlusRenderer(this, renderContext, getOptionValues(cPlusPlusOptions, untypedOptionValues)); } } -function constraintsForType (t: Type): -| { - minMax?: MinMaxConstraint, - minMaxLength?: MinMaxConstraint, - pattern?: string, -} -| undefined { +function constraintsForType(t: Type): + | { + minMax?: MinMaxConstraint; + minMaxLength?: MinMaxConstraint; + pattern?: string; + } + | undefined { const minMax = minMaxValueForType(t); const minMaxLength = minMaxLengthForType(t); const pattern = patternForType(t); @@ -280,7 +279,7 @@ const keywords = [ "final", "transaction_safe", "transaction_safe_dynamic", - "NULL", + "NULL" ]; /// Type to use as an optional if cycle breaking is required @@ -294,43 +293,45 @@ const optionalFactoryAsSharedType = "std::make_shared"; * but in vector or in variant) we can forward declare them; */ export enum IncludeKind { - ForwardDeclare, - Include + ForwardDeclare = "ForwardDeclare", + Include = "Include" } +// FIXME: make these string enums eventually export enum GlobalNames { - ClassMemberConstraints, - ClassMemberConstraintException, - ValueTooLowException, - ValueTooHighException, - ValueTooShortException, - ValueTooLongException, - InvalidPatternException, - CheckConstraint + ClassMemberConstraints = 1, + ClassMemberConstraintException = 2, + ValueTooLowException = 3, + ValueTooHighException = 4, + ValueTooShortException = 5, + ValueTooLongException = 6, + InvalidPatternException = 7, + CheckConstraint = 8 } +// FIXME: make these string enums eventually export enum MemberNames { - MinIntValue, - GetMinIntValue, - SetMinIntValue, - MaxIntValue, - GetMaxIntValue, - SetMaxIntValue, - MinDoubleValue, - GetMinDoubleValue, - SetMinDoubleValue, - MaxDoubleValue, - GetMaxDoubleValue, - SetMaxDoubleValue, - MinLength, - GetMinLength, - SetMinLength, - MaxLength, - GetMaxLength, - SetMaxLength, - Pattern, - GetPattern, - SetPattern + MinIntValue = 1, + GetMinIntValue = 2, + SetMinIntValue = 3, + MaxIntValue = 4, + GetMaxIntValue = 5, + SetMaxIntValue = 6, + MinDoubleValue = 7, + GetMinDoubleValue = 8, + SetMinDoubleValue = 9, + MaxDoubleValue = 10, + GetMaxDoubleValue = 11, + SetMaxDoubleValue = 12, + MinLength = 13, + GetMinLength = 14, + SetMinLength = 15, + MaxLength = 16, + GetMaxLength = 17, + SetMaxLength = 18, + Pattern = 19, + GetPattern = 20, + SetPattern = 21 } interface ConstraintMember { @@ -382,7 +383,7 @@ interface StringType { wrapToString: (inner: Sourcelike) => Sourcelike; } -function addQualifier (qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { +function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { if (qualified.length === 0) { return []; } @@ -391,12 +392,12 @@ function addQualifier (qualifier: Sourcelike, qualified: Sourcelike[]): Sourceli } class WrappingCode { - constructor ( + constructor( private readonly start: Sourcelike[], - private readonly end: Sourcelike[], + private readonly end: Sourcelike[] ) {} - wrap (qualifier: Sourcelike, inner: Sourcelike): Sourcelike { + wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { return [addQualifier(qualifier, this.start), inner, this.end]; } } @@ -418,7 +419,7 @@ class BaseString { public _encodingFunction: Sourcelike; - constructor ( + constructor( stringType: string, constStringType: string, smatch: string, @@ -426,7 +427,7 @@ class BaseString { stringLiteralPrefix: string, toString: WrappingCode, encodingClass: string, - encodingFunction: string, + encodingFunction: string ) { this._stringType = stringType; this._constStringType = constStringType; @@ -438,27 +439,27 @@ class BaseString { this._encodingFunction = encodingFunction; } - public getType (): string { + public getType(): string { return this._stringType; } - public getConstType (): string { + public getConstType(): string { return this._constStringType; } - public getSMatch (): string { + public getSMatch(): string { return this._smatch; } - public getRegex (): string { + public getRegex(): string { return this._regex; } - public createStringLiteral (inner: Sourcelike): Sourcelike { - return [this._stringLiteralPrefix, "\"", inner, "\""]; + public createStringLiteral(inner: Sourcelike): Sourcelike { + return [this._stringLiteralPrefix, '"', inner, '"']; } - public wrapToString (inner: Sourcelike): Sourcelike { + public wrapToString(inner: Sourcelike): Sourcelike { return this._toString.wrap([], inner); } } @@ -508,10 +509,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { protected readonly enumeratorNamingStyle: NamingStyle; - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); @@ -556,14 +557,14 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } // union typeguard - isUnion (t: Type | UnionType): t is UnionType { + isUnion(t: Type | UnionType): t is UnionType { return t.kind === "union"; } // Returns true if the type can be stored in // a stack based optional type. This requires // that the type does not require forward declaration. - isOptionalAsValuePossible (t: Type): boolean { + isOptionalAsValuePossible(t: Type): boolean { if (this.isForwardDeclaredType(t)) return false; if (this.isUnion(t)) { @@ -625,113 +626,113 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { return !this.isCycleBreakerType(t); } - isImplicitCycleBreaker (t: Type): boolean { + isImplicitCycleBreaker(t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } // Is likely to return std::optional or boost::optional - optionalTypeStack (): string { + optionalTypeStack(): string { return this._optionalType; } // Is likely to return std::make_optional or boost::optional - optionalFactoryStack (): string { + optionalFactoryStack(): string { return this._optionalFactory; } // Is likely to return std::shared_ptr - optionalTypeHeap (): string { + optionalTypeHeap(): string { return optionalAsSharedType; } // Is likely to return std::make_shared - optionalFactoryHeap (): string { + optionalFactoryHeap(): string { return optionalFactoryAsSharedType; } // Returns the optional type most suitable for the given type. // Classes that don't require forward declarations can be stored // in std::optional ( or boost::optional ) - optionalType (t: Type): string { + optionalType(t: Type): string { if (this.isOptionalAsValuePossible(t)) return this.optionalTypeStack(); else return this.optionalTypeHeap(); } // Returns a label that can be used to distinguish between // heap and stack based optional handling methods - optionalTypeLabel (t: Type): string { + optionalTypeLabel(t: Type): string { if (this.isOptionalAsValuePossible(t)) return "stack"; else return "heap"; } - protected getConstraintMembers (): ConstraintMember[] { + protected getConstraintMembers(): ConstraintMember[] { return [ { name: MemberNames.MinIntValue, getter: MemberNames.GetMinIntValue, setter: MemberNames.SetMinIntValue, - cppType: "int64_t", + cppType: "int64_t" }, { name: MemberNames.MaxIntValue, getter: MemberNames.GetMaxIntValue, setter: MemberNames.SetMaxIntValue, - cppType: "int64_t", + cppType: "int64_t" }, { name: MemberNames.MinDoubleValue, getter: MemberNames.GetMinDoubleValue, setter: MemberNames.SetMinDoubleValue, - cppType: "double", + cppType: "double" }, { name: MemberNames.MaxDoubleValue, getter: MemberNames.GetMaxDoubleValue, setter: MemberNames.SetMaxDoubleValue, - cppType: "double", + cppType: "double" }, { name: MemberNames.MinLength, getter: MemberNames.GetMinLength, setter: MemberNames.SetMinLength, - cppType: "size_t", + cppType: "size_t" }, { name: MemberNames.MaxLength, getter: MemberNames.GetMaxLength, setter: MemberNames.SetMaxLength, - cppType: "size_t", + cppType: "size_t" }, { name: MemberNames.Pattern, getter: MemberNames.GetPattern, setter: MemberNames.SetPattern, cppType: this._stringType.getType(), - cppConstType: this._stringType.getConstType(), - }, + cppConstType: this._stringType.getConstType() + } ]; } - protected lookupGlobalName (type: GlobalNames): string { + protected lookupGlobalName(type: GlobalNames): string { return defined(this._generatedGlobalNames.get(type)); } - protected lookupMemberName (type: MemberNames): string { + protected lookupMemberName(type: MemberNames): string { return defined(this._generatedMemberNames.get(type)); } - protected addGlobalName (type: GlobalNames): void { + protected addGlobalName(type: GlobalNames): void { const genName = this._namedTypeNameStyle(GlobalNames[type]); this._generatedGlobalNames.set(type, genName); this._forbiddenGlobalNames.push(genName); } - protected addMemberName (type: MemberNames): void { + protected addMemberName(type: MemberNames): void { this._generatedMemberNames.set(type, this._memberNameStyle(MemberNames[type])); } - protected setupGlobalNames (): void { + protected setupGlobalNames(): void { for (const v of numberEnumValues(GlobalNames)) { this.addGlobalName(v); } @@ -741,64 +742,64 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return [...keywords, ...this._forbiddenGlobalNames]; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("types", this._namedTypeNameStyle); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return this._memberNamingFunction; } - protected makeUnionMemberNamer (): null { + protected makeUnionMemberNamer(): null { return null; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("enumerators", makeNameStyle(this.enumeratorNamingStyle, legalizeName)); } - protected makeNamesForPropertyGetterAndSetter ( + protected makeNamesForPropertyGetterAndSetter( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name, + name: Name ): [Name, Name, Name] { const getterName = new DependencyName(this._memberNamingFunction, name.order, lookup => `get_${lookup(name)}`); const mutableGetterName = new DependencyName( this._memberNamingFunction, name.order, - lookup => `getMutable_${lookup(name)}`, + lookup => `getMutable_${lookup(name)}` ); const setterName = new DependencyName(this._memberNamingFunction, name.order, lookup => `set_${lookup(name)}`); return [getterName, mutableGetterName, setterName]; } - protected makePropertyDependencyNames ( + protected makePropertyDependencyNames( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name, + name: Name ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return getterAndSetterNames; } - protected withConst (s: Sourcelike): Sourcelike { + protected withConst(s: Sourcelike): Sourcelike { if (this._options.westConst) { return ["const ", s]; } else { @@ -806,11 +807,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitInclude (global: boolean, name: Sourcelike): void { - this.emitLine("#include ", global ? "<" : "\"", name, global ? ">" : "\""); + protected emitInclude(global: boolean, name: Sourcelike): void { + this.emitLine("#include ", global ? "<" : '"', name, global ? ">" : '"'); } - protected startFile (basename: Sourcelike, includeHelper = true): void { + protected startFile(basename: Sourcelike, includeHelper = true): void { assert(this._currentFilename === undefined, "Previous file wasn't finished"); if (basename !== undefined) { this._currentFilename = this.sourcelikeToString(basename); @@ -828,7 +829,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " json.hpp https://github.com/nlohmann/json", "", " Then include this file, and then do", - "", + "" ]); if (this._options.typeSourceStyle) { @@ -885,25 +886,25 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected finishFile (): void { + protected finishFile(): void { super.finishFile(defined(this._currentFilename)); this._currentFilename = undefined; } - protected get needsTypeDeclarationBeforeUse (): boolean { + protected get needsTypeDeclarationBeforeUse(): boolean { return true; } - protected canBeForwardDeclared (t: Type): boolean { + protected canBeForwardDeclared(t: Type): boolean { const kind = t.kind; return kind === "class"; } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock (line: Sourcelike, withSemicolon: boolean, f: () => void, withIndent = true): void { + protected emitBlock(line: Sourcelike, withSemicolon: boolean, f: () => void, withIndent = true): void { this.emitLine(line, " {"); this.preventBlankLine(); if (withIndent) { @@ -920,7 +921,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitNamespaces (namespaceNames: Iterable, f: () => void): void { + protected emitNamespaces(namespaceNames: Iterable, f: () => void): void { const namesArray = toReadonlyArray(namespaceNames); const first = namesArray[0]; if (first === undefined) { @@ -930,16 +931,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ["namespace ", first], false, () => this.emitNamespaces(namesArray.slice(1), f), - namesArray.length === 1, + namesArray.length === 1 ); } } - protected cppTypeInOptional ( + protected cppTypeInOptional( nonNulls: ReadonlySet, ctx: TypeContext, withIssues: boolean, - forceNarrowString: boolean, + forceNarrowString: boolean ): Sourcelike { if (nonNulls.size === 1) { return this.cppType(defined(iterableFirst(nonNulls)), ctx, withIssues, forceNarrowString, false); @@ -957,19 +958,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: false, - inJsonNamespace: ctx.inJsonNamespace, + inJsonNamespace: ctx.inJsonNamespace }, withIssues, false, - false, - ), + false + ) ); } return [this._variantType, "<", typeList, ">"]; } - protected variantType (u: UnionType, inJsonNamespace: boolean): Sourcelike { + protected variantType(u: UnionType, inJsonNamespace: boolean): Sourcelike { const [maybeNull, nonNulls] = removeNullFromUnion(u, true); assert(nonNulls.size >= 2, "Variant not needed for less than two types."); const indirection = maybeNull !== null; @@ -978,10 +979,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: !indirection, needsOptionalIndirection: !indirection, - inJsonNamespace, + inJsonNamespace }, true, - false, + false ); if (!indirection) { return variant; @@ -990,25 +991,25 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { return [this.optionalType(u), "<", variant, ">"]; } - protected ourQualifier (inJsonNamespace: boolean): Sourcelike { + protected ourQualifier(inJsonNamespace: boolean): Sourcelike { return inJsonNamespace ? [arrayIntercalate("::", this._namespaceNames), "::"] : []; } - protected jsonQualifier (inJsonNamespace: boolean): Sourcelike { + protected jsonQualifier(inJsonNamespace: boolean): Sourcelike { return inJsonNamespace ? [] : "nlohmann::"; } - protected variantIndirection (type: Type, needIndirection: boolean, typeSrc: Sourcelike): Sourcelike { + protected variantIndirection(type: Type, needIndirection: boolean, typeSrc: Sourcelike): Sourcelike { if (!needIndirection) return typeSrc; return [this.optionalType(type), "<", typeSrc, ">"]; } - protected cppType ( + protected cppType( t: Type, ctx: TypeContext, withIssues: boolean, forceNarrowString: boolean, - isOptional: boolean, + isOptional: boolean ): Sourcelike { const inJsonNamespace = ctx.inJsonNamespace; if (isOptional && t instanceof UnionType) { @@ -1027,14 +1028,14 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { isOptional = false; return maybeAnnotated(withIssues, anyTypeIssueAnnotation, [ this.jsonQualifier(inJsonNamespace), - "json", + "json" ]); }, _nullType => { isOptional = false; return maybeAnnotated(withIssues, nullTypeIssueAnnotation, [ this.jsonQualifier(inJsonNamespace), - "json", + "json" ]); }, _boolType => "bool", @@ -1054,19 +1055,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: true, - inJsonNamespace, + inJsonNamespace }, withIssues, forceNarrowString, - false, + false ), - ">", + ">" ], classType => this.variantIndirection( classType, ctx.needsForwardIndirection && this.isForwardDeclaredType(classType) && !isOptional, - [this.ourQualifier(inJsonNamespace), this.nameForNamedType(classType)], + [this.ourQualifier(inJsonNamespace), this.nameForNamedType(classType)] ), mapType => { let keyType = this._stringType.getType(); @@ -1083,13 +1084,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: true, - inJsonNamespace, + inJsonNamespace }, withIssues, forceNarrowString, - false, + false ), - ">", + ">" ]; }, enumType => [this.ourQualifier(inJsonNamespace), this.nameForNamedType(enumType)], @@ -1102,16 +1103,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace, + inJsonNamespace }, withIssues, forceNarrowString, - false, + false ); } else { return [this.ourQualifier(inJsonNamespace), this.nameForNamedType(unionType)]; } - }, + } ); if (!isOptional) return typeSource; return [this.optionalType(t), "<", typeSource, ">"]; @@ -1121,7 +1122,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { * similar to cppType, it practically gathers all the generated types within * 't'. It also records, whether a given sub-type is part of a variant or not. */ - protected generatedTypes (isClassMember: boolean, theType: Type): TypeRecord[] { + protected generatedTypes(isClassMember: boolean, theType: Type): TypeRecord[] { const result: TypeRecord[] = []; const recur = (forceInclude: boolean, isVariant: boolean, l: number, t: Type) => { if (t instanceof ArrayType) { @@ -1132,7 +1133,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude, + forceInclude }); } else if (t instanceof MapType) { recur(true, isVariant, l + 1, t.values); @@ -1142,7 +1143,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude: false, + forceInclude: false }); } else if (t instanceof UnionType) { /** @@ -1166,7 +1167,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { type: t, level: l, variant: true, - forceInclude, + forceInclude }); /** intentional "fall-through", add all subtypes as well - but forced include */ } @@ -1184,15 +1185,15 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { return result; } - protected constraintMember (jsonName: string): string { + protected constraintMember(jsonName: string): string { return this._memberNameStyle(`${jsonName}Constraint`); } - protected emitMember (cppType: Sourcelike, name: Sourcelike): void { + protected emitMember(cppType: Sourcelike, name: Sourcelike): void { this.emitLine(cppType, " ", name, ";"); } - protected emitClassMembers (c: ClassType, constraints: Map | undefined): void { + protected emitClassMembers(c: ClassType, constraints: Map | undefined): void { if (this._options.codeFormat) { this.emitLine("private:"); @@ -1203,13 +1204,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, true, false, - property.isOptional, + property.isOptional ), - name, + name ); if (constraints?.has(jsonName)) { /** FIXME!!! NameStyle will/can collide with other Names */ @@ -1231,28 +1232,28 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, true, false, - property.isOptional, + property.isOptional ), - name, + name ); } else { const [getterName, mutableGetterName, setterName] = defined( - this._gettersAndSettersForPropertyName.get(name), + this._gettersAndSettersForPropertyName.get(name) ); const rendered = this.cppType( property.type, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, true, false, - property.isOptional, + property.isOptional ); /** @@ -1262,8 +1263,8 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { */ const checkConst = this.lookupGlobalName(GlobalNames.CheckConstraint); if ( - property.type instanceof UnionType && property.type.findMember("null") !== undefined || - property.isOptional && property.type.kind !== "null" && property.type.kind !== "any" + (property.type instanceof UnionType && property.type.findMember("null") !== undefined) || + (property.isOptional && property.type.kind !== "null" && property.type.kind !== "any") ) { this.emitLine(rendered, " ", getterName, "() const { return ", name, "; }"); if (constraints?.has(jsonName)) { @@ -1280,7 +1281,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.constraintMember(jsonName), ", *value); this->", name, - " = value; }", + " = value; }" ); } else { this.emitLine("void ", setterName, "(", rendered, " value) { this->", name, " = value; }"); @@ -1302,7 +1303,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.constraintMember(jsonName), ", value); this->", name, - " = value; }", + " = value; }" ); } else { this.emitLine( @@ -1312,7 +1313,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(rendered), " & value) { this->", name, - " = value; }", + " = value; }" ); } } @@ -1322,7 +1323,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } - protected generateClassConstraints (c: ClassType): Map | undefined { + protected generateClassConstraints(c: ClassType): Map | undefined { const res: Map = new Map(); this.forEachClassProperty(c, "none", (_name, jsonName, property) => { const constraints = constraintsForType(property.type); @@ -1335,11 +1336,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, true, false, - property.isOptional, + property.isOptional ); res.set(jsonName, [ @@ -1360,19 +1361,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { pattern === undefined ? this._nulloptType : [ - this._stringType.getType(), - "(", - this._stringType.createStringLiteral([stringEscape(pattern)]), - ")", - ], - ")", + this._stringType.getType(), + "(", + this._stringType.createStringLiteral([stringEscape(pattern)]), + ")" + ], + ")" ]); }); return res.size === 0 ? undefined : res; } - protected emitClass (c: ClassType, className: Name): void { + protected emitClass(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitBlock([this._options.codeFormat ? "class " : "struct ", className], true, () => { const constraints = this.generateClassConstraints(c); @@ -1404,7 +1405,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } - protected emitTopLevelHeaders (t: Type, className: Name): void { + protected emitTopLevelHeaders(t: Type, className: Name): void { // Forward declarations for std::map (need to convert UTF16 <-> UTF8) if (t instanceof MapType && this._stringType !== this.NarrowString) { const ourQualifier = this.ourQualifier(true); @@ -1417,21 +1418,21 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " & j, ", ourQualifier, className, - " & x);", + " & x);" ); this.emitLine("static void to_json(json & j, ", this.withConst([ourQualifier, className]), " & x);"); }); } } - protected emitClassHeaders (className: Name): void { + protected emitClassHeaders(className: Name): void { const ourQualifier = this.ourQualifier(false); this.emitLine("void from_json(", this.withConst("json"), " & j, ", ourQualifier, className, " & x);"); this.emitLine("void to_json(json & j, ", this.withConst([ourQualifier, className]), " & x);"); } - protected emitTopLevelFunction (t: Type, className: Name): void { + protected emitTopLevelFunction(t: Type, className: Name): void { // Function definitions for std::map (need to convert UTF16 <-> UTF8) if (t instanceof MapType && this._stringType !== this.NarrowString) { const ourQualifier = this.ourQualifier(true); @@ -1448,7 +1449,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " & j, ", ourQualifier, className, - "& x)", + "& x)" ], false, () => { @@ -1457,22 +1458,22 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, true, - false, + false ); toType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, false, - false, + false ); this.emitLine([ @@ -1480,11 +1481,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ "j.get<", cppType, - ">()", + ">()" ]), - ";", + ";" ]); - }, + } ); this.emitBlock( @@ -1494,7 +1495,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { className, ">::to_json(json & j, ", this.withConst([ourQualifier, className]), - " & x)", + " & x)" ], false, () => { @@ -1503,35 +1504,35 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, false, - false, + false ); toType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, true, - false, + false ); this.emitLine([ "j = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, "x"), - ";", + ";" ]); - }, + } ); } } - protected emitClassFunctions (c: ClassType, className: Name): void { + protected emitClassFunctions(c: ClassType, className: Name): void { const ourQualifier = this.ourQualifier(false); let cppType: Sourcelike; let toType: Sourcelike; @@ -1562,12 +1563,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(json)])], + [this._stringType.createStringLiteral([stringEscape(json)])] ), - ")", - ], + ")" + ] ), - ";", + ";" ); return; } @@ -1589,20 +1590,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: false, + inJsonNamespace: false }, false, - true, + true ); toType = this.cppTypeInOptional( typeSet, { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: false, + inJsonNamespace: false }, false, - false, + false ); this.emitLine( assignment.wrap( @@ -1621,14 +1622,14 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(json)])], + [this._stringType.createStringLiteral([stringEscape(json)])] ), - ")", - ], - ), - ], + ")" + ] + ) + ] ), - ";", + ";" ); return; } @@ -1639,22 +1640,22 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, false, true, - p.isOptional, + p.isOptional ); toType = this.cppType( propType, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, false, false, - p.isOptional, + p.isOptional ); this.emitLine( assignment.wrap( @@ -1665,17 +1666,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - this._stringType.createStringLiteral([stringEscape(json)]), + this._stringType.createStringLiteral([stringEscape(json)]) ), ").get<", cppType, - ">()", - ]), + ">()" + ]) ), - ";", + ";" ); }); - }, + } ); this.ensureBlankLine(); @@ -1691,22 +1692,22 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, false, false, - p.isOptional, + p.isOptional ); toType = this.cppType( propType, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, false, true, - p.isOptional, + p.isOptional ); const [getterName, ,] = defined(this._gettersAndSettersForPropertyName.get(name)); let getter: Sourcelike[]; @@ -1722,33 +1723,33 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - this._stringType.createStringLiteral([stringEscape(json)]), + this._stringType.createStringLiteral([stringEscape(json)]) ), "] = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, ["x.", getter]), - ";", + ";" ]; if (p.isOptional && this._options.hideNullOptional) { this.emitBlock( [ "if (", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, ["x.", getter]), - ")", + ")" ], false, () => { this.emitLine(assignment); - }, + } ); } else { this.emitLine(assignment); } }); - }, + } ); } - protected emitEnum (e: EnumType, enumName: Name): void { + protected emitEnum(e: EnumType, enumName: Name): void { const caseNames: Sourcelike[] = []; const enumValues = enumCaseValues(e, this.targetLanguage.name); @@ -1767,11 +1768,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("enum class ", enumName, " : ", this._enumType, " { ", caseNames, " };"); } - protected emitUnionTypedefs (u: UnionType, unionName: Name): void { + protected emitUnionTypedefs(u: UnionType, unionName: Name): void { this.emitLine("using ", unionName, " = ", this.variantType(u, false), ";"); } - protected emitUnionHeaders (u: UnionType): void { + protected emitUnionHeaders(u: UnionType): void { // Forward declarations for boost::variant. If none of the Ts were defined by us (e.g. if we have // boost::variant) then we need to specialize nlohmann::adl_serializer for our // variant type. If at least one of the Ts is our type then we could get away with regular adl definitions, @@ -1784,10 +1785,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true, + inJsonNamespace: true }, false, - false, + false ); this.emitLine("template <>"); @@ -1797,7 +1798,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } - protected emitUnionFunctions (u: UnionType): void { + protected emitUnionFunctions(u: UnionType): void { // Function definitions for boost::variant. const ourQualifier = this.ourQualifier(true) as string; @@ -1810,7 +1811,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ["class", "is_object"], ["map", "is_object"], ["array", "is_array"], - ["enum", "is_string"], + ["enum", "is_string"] ]; const nonNulls = removeNullFromUnion(u, true)[1]; const variantType = this.cppTypeInOptional( @@ -1818,10 +1819,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true, + inJsonNamespace: true }, false, - false, + false ); this.emitBlock( @@ -1832,7 +1833,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst("json"), " & j, ", variantType, - " & x)", + " & x)" ], false, () => { @@ -1847,38 +1848,38 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, true, - false, + false ); const toType = this.cppType( typeForKind, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, false, - false, + false ); this.emitLine( "x = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ "j.get<", cppType, - ">()", + ">()" ]), - ";", + ";" ); }); onFirst = false; } - this.emitLine("else throw std::runtime_error(\"Could not deserialise!\");"); - }, + this.emitLine('else throw std::runtime_error("Could not deserialise!");'); + } ); this.ensureBlankLine(); @@ -1896,57 +1897,57 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, false, - false, + false ); const toType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, true, - false, + false ); this.emitLine( "j = ", this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ this._options.boost ? "boost::get<" : "std::get<", cppType, - ">(x)", + ">(x)" ]), - ";", + ";" ); this.emitLine("break;"); }); i++; } - this.emitLine("default: throw std::runtime_error(\"Input JSON does not conform to schema!\");"); + this.emitLine('default: throw std::runtime_error("Input JSON does not conform to schema!");'); }); - }, + } ); } - protected emitEnumHeaders (enumName: Name): void { + protected emitEnumHeaders(enumName: Name): void { const ourQualifier = this.ourQualifier(false); this.emitLine("void from_json(", this.withConst("json"), " & j, ", ourQualifier, enumName, " & x);"); this.emitLine("void to_json(json & j, ", this.withConst([ourQualifier, enumName]), " & x);"); } - private isLargeEnum (e: EnumType) { + private isLargeEnum(e: EnumType) { // This is just an estimation. Someone might want to do some // benchmarks to find the optimum value here return e.cases.size > 15; } - protected emitEnumFunctions (e: EnumType, enumName: Name): void { + protected emitEnumFunctions(e: EnumType, enumName: Name): void { const ourQualifier = this.ourQualifier(false); this.emitBlock( @@ -1961,7 +1962,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ", ", ourQualifier, enumName, - "> enumValues", + "> enumValues" ], true, () => { @@ -1972,17 +1973,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(jsonName)])], + [this._stringType.createStringLiteral([stringEscape(jsonName)])] ), ", ", ourQualifier, enumName, "::", name, - "},", + "}," ); }); - }, + } ); this.emitLine(`auto iter = enumValues.find(j.get<${this._stringType.getType()}>());`); @@ -2000,20 +2001,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(jsonName)])], + [this._stringType.createStringLiteral([stringEscape(jsonName)])] ), ") x = ", ourQualifier, enumName, "::", name, - ";", + ";" ); onFirst = false; }); - this.emitLine("else { throw std::runtime_error(\"Input JSON does not conform to schema!\"); }"); + this.emitLine('else { throw std::runtime_error("Input JSON does not conform to schema!"); }'); } - }, + } ); this.ensureBlankLine(); @@ -2034,20 +2035,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(jsonName)])], + [this._stringType.createStringLiteral([stringEscape(jsonName)])] ), - "; break;", + "; break;" ); }); this.emitLine( - `default: throw std::runtime_error("Unexpected value in enumeration \\"${enumName}\\": " + std::to_string(static_cast(x)));`, + `default: throw std::runtime_error("Unexpected value in enumeration \\"${enumName}\\": " + std::to_string(static_cast(x)));` ); }); - }, + } ); } - protected emitTopLevelTypedef (t: Type, name: Name): void { + protected emitTopLevelTypedef(t: Type, name: Name): void { this.emitLine( "using ", name, @@ -2057,17 +2058,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false, + inJsonNamespace: false }, true, false, - false, + false ), - ";", + ";" ); } - protected emitAllUnionFunctions (): void { + protected emitAllUnionFunctions(): void { this.forEachUniqueUnion( "leading-and-interposing", u => @@ -2077,17 +2078,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true, + inJsonNamespace: true }, false, - false, - ), + false + ) ), - (u: UnionType) => this.emitUnionFunctions(u), + (u: UnionType) => this.emitUnionFunctions(u) ); } - protected emitAllUnionHeaders (): void { + protected emitAllUnionHeaders(): void { this.forEachUniqueUnion( "interposing", u => @@ -2097,17 +2098,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true, + inJsonNamespace: true }, false, - false, - ), + false + ) ), - (u: UnionType) => this.emitUnionHeaders(u), + (u: UnionType) => this.emitUnionHeaders(u) ); } - protected emitOptionalHelpers (): void { + protected emitOptionalHelpers(): void { this.emitLine("#ifndef NLOHMANN_OPT_HELPER"); this.emitLine("#define NLOHMANN_OPT_HELPER"); @@ -2120,7 +2121,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.emitLine("if (!opt) j = nullptr; else j = *opt;"); - }, + } ); this.ensureBlankLine(); @@ -2130,9 +2131,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.emitLine( - `if (j.is_null()) return ${factory}(); else return ${factory}(j.get());`, + `if (j.is_null()) return ${factory}(); else return ${factory}(j.get());` ); - }, + } ); }); }; @@ -2144,7 +2145,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("#endif"); } - protected emitDeclaration (decl: Declaration): void { + protected emitDeclaration(decl: Declaration): void { if (decl.kind === "forward") { if (this._options.codeFormat) { this.emitLine("class ", this.nameForNamedType(decl.type), ";"); @@ -2168,17 +2169,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitGetterSetter (t: string, getterName: string, setterName: string, memberName: string): void { + protected emitGetterSetter(t: string, getterName: string, setterName: string, memberName: string): void { this.emitLine("void ", setterName, "(", t, " ", memberName, ") { this->", memberName, " = ", memberName, "; }"); this.emitLine("auto ", getterName, "() const { return ", memberName, "; }"); } - protected emitNumericCheckConstraints ( + protected emitNumericCheckConstraints( checkConst: string, classConstraint: string, getterMinValue: string, getterMaxValue: string, - cppType: string, + cppType: string ): void { this.emitBlock( [ @@ -2190,7 +2191,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(classConstraint), " & c, ", cppType, - " value)", + " value)" ], false, () => { @@ -2213,9 +2214,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMinValue, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");", + ");" ); - }, + } ); this.ensureBlankLine(); @@ -2238,17 +2239,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMaxValue, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");", + ");" ); - }, + } ); this.ensureBlankLine(); - }, + } ); this.ensureBlankLine(); } - protected emitConstraintClasses (): void { + protected emitConstraintClasses(): void { const ourQualifier = this.ourQualifier(false) as string; const getterMinIntValue = this.lookupMemberName(MemberNames.GetMinIntValue); @@ -2291,7 +2292,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { withDefault(member.cppConstType, member.cppType), this.lookupMemberName(member.getter), this.lookupMemberName(member.setter), - this.lookupMemberName(member.name), + this.lookupMemberName(member.name) ); } }); @@ -2309,9 +2310,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - ["msg"], + ["msg"] ), - ") {}", + ") {}" ); }); this.ensureBlankLine(); @@ -2321,7 +2322,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { GlobalNames.ValueTooHighException, GlobalNames.ValueTooShortException, GlobalNames.ValueTooLongException, - GlobalNames.InvalidPatternException, + GlobalNames.InvalidPatternException ]; for (const ex of exceptions) { @@ -2340,7 +2341,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { classConstraint, getterMinDoubleValue, getterMaxDoubleValue, - "double", + "double" ); this.emitBlock( @@ -2353,7 +2354,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(classConstraint), " & c, ", this._stringType.getConstType(), - " value)", + " value)" ], false, () => { @@ -2365,7 +2366,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._nulloptType, " && value.length() < *c.", getterMinLength, - "())", + "())" ], false, () => { @@ -2384,9 +2385,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMinLength, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");", + ");" ); - }, + } ); this.ensureBlankLine(); @@ -2398,7 +2399,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._nulloptType, " && value.length() > *c.", getterMaxLength, - "())", + "())" ], false, () => { @@ -2417,9 +2418,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.wrapToString(["*c.", getterMaxLength, "()"]), " + ", this._stringType.createStringLiteral([")"]), - ");", + ");" ); - }, + } ); this.ensureBlankLine(); @@ -2430,7 +2431,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._stringType.getRegex(), "( *c.", getterPattern, - "() ));", + "() ));" ); this.emitBlock(["if (result.empty())"], false, () => { this.emitLine( @@ -2446,16 +2447,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { getterPattern, "() + ", this._stringType.createStringLiteral([")"]), - ");", + ");" ); }); }); this.ensureBlankLine(); - }, + } ); } - protected emitHelperFunctions (): void { + protected emitHelperFunctions(): void { this._stringType.emitHelperFunctions(); if ( @@ -2493,7 +2494,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("return j.at(property).get();"); }); this.emitLine("return json();"); - }, + } ); this.ensureBlankLine(); @@ -2503,7 +2504,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.emitLine("return get_untyped(j, property.data());"); - }, + } ); this.emitLine("#endif"); @@ -2526,7 +2527,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst("json"), " & j, ", this.withConst("char"), - " * property)", + " * property)" ], false, () => { @@ -2535,7 +2536,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("return j.at(property).get<", optionalType, ">();"); }); this.emitLine("return ", optionalType, "();"); - }, + } ); this.ensureBlankLine(); @@ -2547,12 +2548,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { optionalType, ` get_${label}_optional(`, this.withConst("json"), - " & j, std::string property)", + " & j, std::string property)" ], false, () => { this.emitLine(`return get_${label}_optional(j, property.data());`); - }, + } ); }; @@ -2565,7 +2566,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitExtraIncludes (): void { + protected emitExtraIncludes(): void { this.ensureBlankLine(); if (this._options.codeFormat) { @@ -2592,7 +2593,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitHelper (): void { + protected emitHelper(): void { this.startFile("helper.hpp", false); this.emitExtraIncludes(); @@ -2613,7 +2614,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.finishFile(); } - protected emitTypes (): void { + protected emitTypes(): void { if (!this._options.justTypes) { this.emitLine("using nlohmann::json;"); this.ensureBlankLine(); @@ -2625,24 +2626,24 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading", (t: Type, name: Name) => this.emitTopLevelTypedef(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); } - protected gatherUserNamespaceForwardDecls (): Sourcelike[] { + protected gatherUserNamespaceForwardDecls(): Sourcelike[] { return this.gatherSource(() => { this.forEachObject("leading-and-interposing", (_: any, className: Name) => - this.emitClassHeaders(className), + this.emitClassHeaders(className) ); this.forEachEnum("leading-and-interposing", (_: any, enumName: Name) => this.emitEnumHeaders(enumName)); }); } - protected gatherNlohmannNamespaceForwardDecls (): Sourcelike[] { + protected gatherNlohmannNamespaceForwardDecls(): Sourcelike[] { return this.gatherSource(() => { this.forEachTopLevel("leading-and-interposing", (t: Type, className: Name) => - this.emitTopLevelHeaders(t, className), + this.emitTopLevelHeaders(t, className) ); this.ensureBlankLine(); @@ -2651,21 +2652,21 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }); } - protected emitUserNamespaceImpls (): void { + protected emitUserNamespaceImpls(): void { this.forEachObject("leading-and-interposing", (c: ClassType, className: Name) => - this.emitClassFunctions(c, className), + this.emitClassFunctions(c, className) ); this.forEachEnum("leading-and-interposing", (e: EnumType, enumName: Name) => - this.emitEnumFunctions(e, enumName), + this.emitEnumFunctions(e, enumName) ); } - protected emitNlohmannNamespaceImpls (): void { + protected emitNlohmannNamespaceImpls(): void { this.forEachTopLevel( "leading-and-interposing", (t: Type, name: Name) => this.emitTopLevelFunction(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); this.ensureBlankLine(); @@ -2673,7 +2674,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitAllUnionFunctions(); } - protected emitGenerators (): void { + protected emitGenerators(): void { if (this._options.justTypes) { let didEmit = false; const gathered = this.gatherSource(() => @@ -2681,9 +2682,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { didEmit = this.forEachTopLevel( "none", (t: Type, name: Name) => this.emitTopLevelTypedef(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); - }), + }) ); if (didEmit) { this.emitGatheredSource(gathered); @@ -2720,7 +2721,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitSingleSourceStructure (proposedFilename: string): void { + protected emitSingleSourceStructure(proposedFilename: string): void { this.startFile(proposedFilename); this._generatedFiles.add(proposedFilename); @@ -2744,7 +2745,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.finishFile(); } - protected updateIncludes (isClassMember: boolean, includes: IncludeMap, propertyType: Type, _defName: string): void { + protected updateIncludes(isClassMember: boolean, includes: IncludeMap, propertyType: Type, _defName: string): void { const propTypes = this.generatedTypes(isClassMember, propertyType); for (const t of propTypes) { @@ -2797,7 +2798,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitIncludes (c: ClassType | UnionType | EnumType, defName: string): void { + protected emitIncludes(c: ClassType | UnionType | EnumType, defName: string): void { /** * Need to generate "includes", in terms 'c' has members, which * are defined by others @@ -2864,7 +2865,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitDefinition (d: ClassType | EnumType | UnionType, defName: Name): void { + protected emitDefinition(d: ClassType | EnumType | UnionType, defName: Name): void { const name = `${this.sourcelikeToString(defName)}.hpp`; this.startFile(name, true); this._generatedFiles.add(name); @@ -2888,7 +2889,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.finishFile(); } - protected emitMultiSourceStructure (proposedFilename: string): void { + protected emitMultiSourceStructure(proposedFilename: string): void { if (!this._options.justTypes && this.haveNamedTypes) { this.emitHelper(); @@ -2914,7 +2915,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }, (u, n) => { this.emitDefinition(u, n); - }, + } ); /** @@ -2936,7 +2937,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading", (t: Type, name: Name) => this.emitTopLevelTypedef(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); }); @@ -2944,7 +2945,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected emitSourceStructure (proposedFilename: string): void { + protected emitSourceStructure(proposedFilename: string): void { this._generatedFiles.clear(); /** Gather all the unique/custom types used by the schema */ @@ -2959,13 +2960,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: false, + inJsonNamespace: false }, true, false, - false, - ), - ), + false + ) + ) ]); } @@ -2982,17 +2983,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected isConversionRequired (t: Type) { + protected isConversionRequired(t: Type) { const originalType = this.cppType( t, { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, false, - false, + false ); const newType = this.cppType( @@ -3000,18 +3001,18 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true, + inJsonNamespace: true }, false, true, - false, + false ); return originalType !== newType; } - public NarrowString = new class extends BaseString implements StringType { - constructor () { + public NarrowString = new (class extends BaseString implements StringType { + constructor() { super( "std::string", "const std::string & ", @@ -3020,26 +3021,26 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { "", new WrappingCode(["std::to_string("], [")"]), "", - "", + "" ); } - public wrapEncodingChange ( + public wrapEncodingChange( _qualifier: Sourcelike[], _fromType: Sourcelike, _toType: Sourcelike, - inner: Sourcelike, + inner: Sourcelike ): Sourcelike { return inner; } - public emitHelperFunctions (): void { + public emitHelperFunctions(): void { return; } - }(); + })(); - public WideString = new class extends BaseString implements StringType { - constructor (public superThis: CPlusPlusRenderer) { + public WideString = new (class extends BaseString implements StringType { + constructor(public superThis: CPlusPlusRenderer) { super( "std::wstring", "const std::wstring & ", @@ -3048,15 +3049,15 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { "L", new WrappingCode(["std::to_wstring("], [")"]), "Utf16_Utf8", - "convert", + "convert" ); } - public wrapEncodingChange ( + public wrapEncodingChange( qualifier: Sourcelike[], fromType: Sourcelike, toType: Sourcelike, - inner: Sourcelike, + inner: Sourcelike ): Sourcelike { if (this.superThis.sourcelikeToString(fromType) === this.superThis.sourcelikeToString(toType)) { return inner; @@ -3072,11 +3073,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._encodingFunction, "(", inner, - ")", + ")" ]; } - public emitHelperFunctions (): void { + public emitHelperFunctions(): void { this.superThis.emitLine("template"); this.superThis.emitLine("struct tag {};"); this.superThis.ensureBlankLine(); @@ -3090,9 +3091,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.superThis.emitLine( - "if (ptr == nullptr) return std::unique_ptr(); else return std::unique_ptr(new TT(Utf16_Utf8::convert(*ptr)));", + "if (ptr == nullptr) return std::unique_ptr(); else return std::unique_ptr(new TT(Utf16_Utf8::convert(*ptr)));" ); - }, + } ); this.superThis.ensureBlankLine(); @@ -3108,7 +3109,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.superThis.emitLine("it++;"); }); this.superThis.emitLine("return newVector;"); - }, + } ); this.superThis.ensureBlankLine(); @@ -3121,12 +3122,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.superThis.emitLine("auto newMap = std::map();"); this.superThis.emitBlock(["while (it != m.end())"], false, () => { this.superThis.emitLine( - "newMap.insert(std::pair(Utf16_Utf8::convert(it->first), Utf16_Utf8::convert(it->second)));", + "newMap.insert(std::pair(Utf16_Utf8::convert(it->first), Utf16_Utf8::convert(it->second)));" ); this.superThis.emitLine("it++;"); }); this.superThis.emitLine("return newMap;"); - }, + } ); this.superThis.ensureBlankLine(); @@ -3141,9 +3142,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.superThis.emitLine( - "return std::wstring_convert, wchar_t>{}.from_bytes(str.data());", + "return std::wstring_convert, wchar_t>{}.from_bytes(str.data());" ); - }, + } ); this.superThis.ensureBlankLine(); @@ -3152,9 +3153,9 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { false, () => { this.superThis.emitLine( - "return std::wstring_convert, wchar_t>{}.to_bytes(str.data());", + "return std::wstring_convert, wchar_t>{}.to_bytes(str.data());" ); - }, + } ); this.superThis.ensureBlankLine(); @@ -3172,10 +3173,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.superThis.emitLine( "return ", this.superThis.ourQualifier(false), - "Utf16_Utf8::convert(s.str()); ", + "Utf16_Utf8::convert(s.str()); " ); }); this.superThis.ensureBlankLine(); } - }(this); + })(this); } diff --git a/packages/quicktype-core/src/language/CSharp.ts b/packages/quicktype-core/src/language/CSharp.ts index 9ffc68669..e9ee7be51 100644 --- a/packages/quicktype-core/src/language/CSharp.ts +++ b/packages/quicktype-core/src/language/CSharp.ts @@ -5,41 +5,32 @@ import { type ClassProperty, type TransformedStringTypeKind, type PrimitiveStringTypeKind, - type PrimitiveType, -} from "../Type"; -import { - EnumType, - UnionType, - ClassType, - ArrayType, + type PrimitiveType } from "../Type"; +import { EnumType, UnionType, ClassType, ArrayType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion, directlyReachableSingleNamedType } from "../TypeUtils"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated, modifySource } from "../Source"; -import { - type WordInName, -} from "../support/Strings"; +import { type WordInName } from "../support/Strings"; import { utf16LegalizeCharacters, utf16StringEscape, splitIntoWords, combineWords, firstUpperWordStyle, - camelCase, + camelCase } from "../support/Strings"; import { defined, assert, panic, assertNever } from "../support/Support"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { DependencyName, funPrefixNamer, SimpleName } from "../Naming"; -import { type ForbiddenWordsInfo} from "../ConvenienceRenderer"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer, inferredNameOrder } from "../ConvenienceRenderer"; import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { StringOption, EnumOption, BooleanOption, getOptionValues } from "../RendererOptions"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type StringTypeMapping } from "../TypeBuilder"; -import { - type Transformer, - type Transformation} from "../Transformers"; +import { type Transformer, type Transformation } from "../Transformers"; import { followTargetType, transformationForType, @@ -56,35 +47,36 @@ import { ArrayDecodingTransformer, ArrayEncodingTransformer, MinMaxLengthCheckTransformer, - MinMaxValueTransformer, + MinMaxValueTransformer } from "../Transformers"; import { type RenderContext } from "../Renderer"; import { minMaxLengthForType, minMaxValueForType } from "../attributes/Constraints"; import unicode from "unicode-properties"; export enum Framework { - Newtonsoft, - SystemTextJson + Newtonsoft = "Newtonsoft", + SystemTextJson = "SystemTextJson" } export type Version = 5 | 6; export interface OutputFeatures { - attributes: boolean; helpers: boolean; + attributes: boolean; + helpers: boolean; } export enum AccessModifier { - None, - Public, - Internal + None = "None", + Public = "Public", + Internal = "Internal" } export type CSharpTypeForAny = "object" | "dynamic"; -function noFollow (t: Type): Type { +function noFollow(t: Type): Type { return t; } -function needTransformerForType (t: Type): "automatic" | "manual" | "nullable" | "none" { +function needTransformerForType(t: Type): "automatic" | "manual" | "nullable" | "none" { if (t instanceof UnionType) { const maybeNullable = nullableFromUnion(t); if (maybeNullable === null) return "automatic"; @@ -108,7 +100,7 @@ function needTransformerForType (t: Type): "automatic" | "manual" | "nullable" | return "none"; } -function alwaysApplyTransformation (xf: Transformation): boolean { +function alwaysApplyTransformation(xf: Transformation): boolean { const t = xf.targetType; if (t instanceof EnumType) return true; if (t instanceof UnionType) return nullableFromUnion(t) === null; @@ -118,7 +110,7 @@ function alwaysApplyTransformation (xf: Transformation): boolean { /** * The C# type for a given transformed string type. */ -function csTypeForTransformedStringType (t: PrimitiveType): Sourcelike { +function csTypeForTransformedStringType(t: PrimitiveType): Sourcelike { switch (t.kind) { case "date-time": return "DateTimeOffset"; @@ -137,23 +129,23 @@ export const cSharpOptions = { "Serialization framework", [ ["NewtonSoft", Framework.Newtonsoft], - ["SystemTextJson", Framework.SystemTextJson], + ["SystemTextJson", Framework.SystemTextJson] ], - "NewtonSoft", + "NewtonSoft" ), useList: new EnumOption("array-type", "Use T[] or List", [ ["array", false], - ["list", true], + ["list", true] ]), dense: new EnumOption( "density", "Property density", [ ["normal", false], - ["dense", true], + ["dense", true] ], "normal", - "secondary", + "secondary" ), // FIXME: Do this via a configurable named eventually. namespace: new StringOption("namespace", "Generated namespace", "NAME", "QuickType"), @@ -162,58 +154,58 @@ export const cSharpOptions = { "C# version", [ ["5", 5], - ["6", 6], + ["6", 6] ], "6", - "secondary", + "secondary" ), virtual: new BooleanOption("virtual", "Generate virtual properties", false), typeForAny: new EnumOption( "any-type", - "Type to use for \"any\"", + 'Type to use for "any"', [ ["object", "object"], - ["dynamic", "dynamic"], + ["dynamic", "dynamic"] ], "object", - "secondary", + "secondary" ), useDecimal: new EnumOption( "number-type", "Type to use for numbers", [ ["double", false], - ["decimal", true], + ["decimal", true] ], "double", - "secondary", + "secondary" ), features: new EnumOption("features", "Output features", [ ["complete", { namespaces: true, helpers: true, attributes: true }], ["attributes-only", { namespaces: true, helpers: false, attributes: true }], ["just-types-and-namespace", { namespaces: true, helpers: false, attributes: false }], - ["just-types", { namespaces: true, helpers: false, attributes: false }], + ["just-types", { namespaces: true, helpers: false, attributes: false }] ]), baseclass: new EnumOption( "base-class", "Base class", [ ["EntityData", "EntityData"], - ["Object", undefined], + ["Object", undefined] ], "Object", - "secondary", + "secondary" ), checkRequired: new BooleanOption("check-required", "Fail if required properties are missing", false), - keepPropertyName: new BooleanOption("keep-property-name", "Keep original field name generate", false), + keepPropertyName: new BooleanOption("keep-property-name", "Keep original field name generate", false) }; export class CSharpTargetLanguage extends TargetLanguage { - constructor () { + constructor() { super("C#", ["cs", "csharp"], "cs"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ cSharpOptions.framework, cSharpOptions.namespace, @@ -226,11 +218,11 @@ export class CSharpTargetLanguage extends TargetLanguage { cSharpOptions.features, cSharpOptions.baseclass, cSharpOptions.checkRequired, - cSharpOptions.keepPropertyName, + cSharpOptions.keepPropertyName ]; } - get stringTypeMapping (): StringTypeMapping { + get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date-time"); mapping.set("time", "date-time"); @@ -242,22 +234,22 @@ export class CSharpTargetLanguage extends TargetLanguage { return mapping; } - get supportsUnionsWithBothNumberTypes (): boolean { + get supportsUnionsWithBothNumberTypes(): boolean { return true; } - get supportsOptionalClassProperties (): boolean { + get supportsOptionalClassProperties(): boolean { return true; } - needsTransformerForType (t: Type): boolean { + needsTransformerForType(t: Type): boolean { const need = needTransformerForType(t); return need !== "none" && need !== "nullable"; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): ConvenienceRenderer { const options = getOptionValues(cSharpOptions, untypedOptionValues); @@ -266,13 +258,13 @@ export class CSharpTargetLanguage extends TargetLanguage { return new NewtonsoftCSharpRenderer( this, renderContext, - getOptionValues(newtonsoftCSharpOptions, untypedOptionValues), + getOptionValues(newtonsoftCSharpOptions, untypedOptionValues) ); case Framework.SystemTextJson: return new SystemTextJsonCSharpRenderer( this, renderContext, - getOptionValues(systemTextJsonCSharpOptions, untypedOptionValues), + getOptionValues(systemTextJsonCSharpOptions, untypedOptionValues) ); default: return assertNever(options.framework); @@ -288,7 +280,7 @@ const denseJsonPropertyName = "J"; const denseRequiredEnumName = "R"; const denseNullValueHandlingEnumName = "N"; -function isStartCharacter (utf16Unit: number): boolean { +function isStartCharacter(utf16Unit: number): boolean { if (unicode.isAlphabetic(utf16Unit)) { return true; } @@ -296,7 +288,7 @@ function isStartCharacter (utf16Unit: number): boolean { return utf16Unit === 0x5f; // underscore } -function isPartCharacter (utf16Unit: number): boolean { +function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); if (["Nd", "Pc", "Mn", "Mc"].includes(category)) { return true; @@ -307,7 +299,7 @@ function isPartCharacter (utf16Unit: number): boolean { const legalizeName = utf16LegalizeCharacters(isPartCharacter); -function csNameStyle (original: string): string { +function csNameStyle(original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -317,11 +309,11 @@ function csNameStyle (original: string): string { firstUpperWordStyle, firstUpperWordStyle, "", - isStartCharacter, + isStartCharacter ); } -function csNameStyleKeep (original: string): string { +function csNameStyleKeep(original: string): string { const keywords = [ "abstract", "as", @@ -399,14 +391,14 @@ function csNameStyleKeep (original: string): string { "virtual", "void", "volatile", - "while", + "while" ]; const words: WordInName[] = [ { word: original, - isAcronym: false, - }, + isAcronym: false + } ]; const result = combineWords( @@ -417,13 +409,13 @@ function csNameStyleKeep (original: string): string { x => x, x => x, "", - isStartCharacter, + isStartCharacter ); return keywords.includes(result) ? "@" + result : result; } -function isValueType (t: Type): boolean { +function isValueType(t: Type): boolean { if (t instanceof UnionType) { return nullableFromUnion(t) === null; } @@ -432,19 +424,19 @@ function isValueType (t: Type): boolean { } export class CSharpRenderer extends ConvenienceRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _csOptions: OptionValues, + private readonly _csOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return ["QuickType", "Type", "System", "Console", "Exception", "DateTimeOffset", "Guid", "Uri"]; } - protected forbiddenForObjectProperties (_: ClassType, classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_: ClassType, classNamed: Name): ForbiddenWordsInfo { return { names: [ classNamed, @@ -454,54 +446,54 @@ export class CSharpRenderer extends ConvenienceRenderer { "Equals", "GetType", "MemberwiseClone", - "ReferenceEquals", + "ReferenceEquals" ], - includeGlobalForbidden: false, + includeGlobalForbidden: false }; } - protected forbiddenForUnionMembers (_: UnionType, unionNamed: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_: UnionType, unionNamed: Name): ForbiddenWordsInfo { return { names: [unionNamed], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return namingFunction; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return this._csOptions.keepPropertyName ? namingFunctionKeep : namingFunction; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return namingFunction; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return namingFunction; } - protected unionNeedsName (u: UnionType): boolean { + protected unionNeedsName(u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { // If the top-level type doesn't contain any classes or unions // we have to define a class just for the `FromJson` method, in // emitFromJsonForTopLevel. return directlyReachableSingleNamedType(type); } - protected emitBlock (f: () => void, semicolon = false): void { + protected emitBlock(f: () => void, semicolon = false): void { this.emitLine("{"); this.indent(f); this.emitLine("}", semicolon ? ";" : ""); } - protected get doubleType (): string { + protected get doubleType(): string { return this._csOptions.useDecimal ? "decimal" : "double"; } - protected csType (t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { + protected csType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { const actualType = follow(t); return matchType( actualType, @@ -527,11 +519,11 @@ export class CSharpRenderer extends ConvenienceRenderer { if (nullable !== null) return this.nullableCSType(nullable, noFollow); return this.nameForNamedType(unionType); }, - transformedStringType => csTypeForTransformedStringType(transformedStringType), + transformedStringType => csTypeForTransformedStringType(transformedStringType) ); } - protected nullableCSType (t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { + protected nullableCSType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { t = followTargetType(t); const csType = this.csType(t, follow, withIssues); if (isValueType(t)) { @@ -541,17 +533,17 @@ export class CSharpRenderer extends ConvenienceRenderer { } } - protected baseclassForType (_t: Type): Sourcelike | undefined { + protected baseclassForType(_t: Type): Sourcelike | undefined { return undefined; } - protected emitType ( + protected emitType( description: string[] | undefined, accessModifier: AccessModifier, declaration: Sourcelike, name: Sourcelike, baseclass: Sourcelike | undefined, - emitter: () => void, + emitter: () => void ): void { switch (accessModifier) { case AccessModifier.Public: @@ -574,16 +566,16 @@ export class CSharpRenderer extends ConvenienceRenderer { this.emitBlock(emitter); } - protected attributesForProperty ( + protected attributesForProperty( _property: ClassProperty, _name: Name, _c: ClassType, - _jsonName: string, + _jsonName: string ): Sourcelike[] | undefined { return undefined; } - protected propertyDefinition (property: ClassProperty, name: Name, _c: ClassType, _jsonName: string): Sourcelike { + protected propertyDefinition(property: ClassProperty, name: Name, _c: ClassType, _jsonName: string): Sourcelike { const t = property.type; const csType = property.isOptional ? this.nullableCSType(t, followTargetType, true) @@ -596,7 +588,7 @@ export class CSharpRenderer extends ConvenienceRenderer { return [...propertyArray, csType, " ", name, " { get; set; }"]; } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { const start = "/// "; if (this._csOptions.dense) { this.emitLine(start, lines.join("; "), ""); @@ -605,11 +597,11 @@ export class CSharpRenderer extends ConvenienceRenderer { } } - protected blankLinesBetweenAttributes (): boolean { + protected blankLinesBetweenAttributes(): boolean { return false; } - private emitClassDefinition (c: ClassType, className: Name): void { + private emitClassDefinition(c: ClassType, className: Name): void { this.emitType( this.descriptionForType(c), AccessModifier.Public, @@ -629,7 +621,7 @@ export class CSharpRenderer extends ConvenienceRenderer { if (attributes === undefined) { if ( // Descriptions should be preceded by an empty line - !isFirstProperty && description !== undefined || + (!isFirstProperty && description !== undefined) || // If the previous property has a description, leave an empty line previousDescription !== undefined ) { @@ -656,11 +648,11 @@ export class CSharpRenderer extends ConvenienceRenderer { if (columns.length > 0) { this.emitTable(columns); } - }, + } ); } - private emitUnionDefinition (u: UnionType, unionName: Name): void { + private emitUnionDefinition(u: UnionType, unionName: Name): void { const nonNulls = removeNullFromUnion(u, true)[1]; this.emitType( this.descriptionForType(u), @@ -676,23 +668,23 @@ export class CSharpRenderer extends ConvenienceRenderer { this.ensureBlankLine(); const nullTests: Sourcelike[] = Array.from(nonNulls).map(t => [ this.nameForUnionMember(u, t), - " == null", + " == null" ]); this.ensureBlankLine(); this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { const csType = this.csType(t); this.emitExpressionMember( ["public static implicit operator ", unionName, "(", csType, " ", fieldName, ")"], - ["new ", unionName, " { ", fieldName, " = ", fieldName, " }"], + ["new ", unionName, " { ", fieldName, " = ", fieldName, " }"] ); }); if (u.findMember("null") === undefined) return; this.emitExpressionMember("public bool IsNull", arrayIntercalate(" && ", nullTests), true); - }, + } ); } - private emitEnumDefinition (e: EnumType, enumName: Name): void { + private emitEnumDefinition(e: EnumType, enumName: Name): void { const caseNames: Sourcelike[] = []; this.forEachEnumCase(e, "none", name => { if (caseNames.length > 0) caseNames.push(", "); @@ -702,7 +694,7 @@ export class CSharpRenderer extends ConvenienceRenderer { this.emitLine("public enum ", enumName, " { ", caseNames, " };"); } - protected emitExpressionMember (declare: Sourcelike, define: Sourcelike, isProperty = false): void { + protected emitExpressionMember(declare: Sourcelike, define: Sourcelike, isProperty = false): void { if (this._csOptions.version === 5) { this.emitLine(declare); this.emitBlock(() => { @@ -724,7 +716,7 @@ export class CSharpRenderer extends ConvenienceRenderer { condition: (t: T) => Sourcelike, withBlock: boolean, withReturn: boolean, - f: (t: T) => void, + f: (t: T) => void ): void { assert(!withReturn || withBlock, "Can only have return with block"); for (const t of types) { @@ -742,40 +734,40 @@ export class CSharpRenderer extends ConvenienceRenderer { } } - protected emitUsing (ns: Sourcelike): void { + protected emitUsing(ns: Sourcelike): void { this.emitLine("using ", ns, ";"); } - protected emitUsings (): void { + protected emitUsings(): void { for (const ns of ["System", "System.Collections.Generic"]) { this.emitUsing(ns); } } - protected emitRequiredHelpers (): void { + protected emitRequiredHelpers(): void { return; } - private emitTypesAndSupport (): void { + private emitTypesAndSupport(): void { this.forEachObject("leading-and-interposing", (c: ClassType, name: Name) => this.emitClassDefinition(c, name)); this.forEachEnum("leading-and-interposing", (e, name) => this.emitEnumDefinition(e, name)); this.forEachUnion("leading-and-interposing", (u, name) => this.emitUnionDefinition(u, name)); this.emitRequiredHelpers(); } - protected emitDefaultLeadingComments (): void { + protected emitDefaultLeadingComments(): void { return; } - protected emitDefaultFollowingComments (): void { + protected emitDefaultFollowingComments(): void { return; } - protected needNamespace (): boolean { + protected needNamespace(): boolean { return true; } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -809,10 +801,10 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { private readonly _needNamespaces: boolean; - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext, _options); this._needHelpers = _options.features.helpers; @@ -820,7 +812,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this._needNamespaces = _options.features.namespaces; } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { const forbidden = [ "Converter", "JsonConverter", @@ -832,7 +824,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { "MetadataPropertyHandling", "DateParseHandling", "FromJson", - "Required", + "Required" ]; if (this._options.dense) { forbidden.push("J", "R", "N"); @@ -845,13 +837,13 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return super.forbiddenNamesForGlobalNamespace().concat(forbidden); } - protected forbiddenForObjectProperties (c: ClassType, className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { const result = super.forbiddenForObjectProperties(c, className); result.names = result.names.concat(["ToJson", "FromJson", "Required"]); return result; } - protected makeNameForTransformation (xf: Transformation, typeName: Name | undefined): Name { + protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { if (typeName === undefined) { let xfer = xf.transformer; if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { @@ -864,19 +856,19 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); } - protected makeNamedTypeDependencyNames (t: Type, name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { if (!(t instanceof EnumType)) return []; const extensionsName = new DependencyName( namingFunction, name.order + 30, - lookup => `${lookup(name)}_extensions`, + lookup => `${lookup(name)}_extensions` ); this._enumExtensionsNames.set(name, extensionsName); return [extensionsName]; } - protected emitUsings (): void { + protected emitUsings(): void { // FIXME: We need System.Collections.Generic whenever we have maps or use List. if (!this._needAttributes && !this._needHelpers) return; @@ -898,11 +890,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } } - protected baseclassForType (_t: Type): Sourcelike | undefined { + protected baseclassForType(_t: Type): Sourcelike | undefined { return this._options.baseclass; } - protected emitDefaultLeadingComments (): void { + protected emitDefaultLeadingComments(): void { if (!this._needHelpers) return; this.emitLine("// "); @@ -910,7 +902,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.emitLine( "// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do", this.topLevels.size === 1 ? "" : " one of these", - ":", + ":" ); this.emitLine("//"); this.emitLine("// using ", this._options.namespace, ";"); @@ -927,7 +919,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { }); } - private converterForType (t: Type): Name | undefined { + private converterForType(t: Type): Name | undefined { let xf = transformationForType(t); if (xf === undefined && t instanceof UnionType) { @@ -945,11 +937,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return defined(this.nameForTransformation(t)); } - protected attributesForProperty ( + protected attributesForProperty( property: ClassProperty, _name: Name, _c: ClassType, - jsonName: string, + jsonName: string ): Sourcelike[] | undefined { if (!this._needAttributes) return undefined; @@ -964,7 +956,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const nullValueHandling = isOptional && !isNullable ? [", NullValueHandling = ", nullValueHandlingClass, ".Ignore"] : []; let required: Sourcelike; - if (!this._options.checkRequired || isOptional && isNullable) { + if (!this._options.checkRequired || (isOptional && isNullable)) { required = [nullValueHandling]; } else if (isOptional && !isNullable) { required = [", Required = ", requiredClass, ".DisallowNull", nullValueHandling]; @@ -974,7 +966,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { required = [", Required = ", requiredClass, ".Always", nullValueHandling]; } - attributes.push(["[", jsonProperty, "(\"", escapedName, "\"", required, ")]"]); + attributes.push(["[", jsonProperty, '("', escapedName, '"', required, ")]"]); const converter = this.converterForType(property.type); if (converter !== undefined) { @@ -984,16 +976,16 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return attributes; } - protected blankLinesBetweenAttributes (): boolean { + protected blankLinesBetweenAttributes(): boolean { return this._needAttributes && !this._options.dense; } // The "this" type can't be `dynamic`, so we have to force it to `object`. - private topLevelResultType (t: Type): Sourcelike { + private topLevelResultType(t: Type): Sourcelike { return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); } - private emitFromJsonForTopLevel (t: Type, name: Name): void { + private emitFromJsonForTopLevel(t: Type, name: Name): void { if (t instanceof EnumType) return; let partial: string; @@ -1012,33 +1004,33 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { // FIXME: Make FromJson a Named this.emitExpressionMember( ["public static ", csType, " FromJson(string json)"], - ["JsonConvert.DeserializeObject<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"], + ["JsonConvert.DeserializeObject<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] ); }); } - private emitDecoderSwitch (emitBody: () => void): void { + private emitDecoderSwitch(emitBody: () => void): void { this.emitLine("switch (reader.TokenType)"); this.emitBlock(emitBody); } - private emitTokenCase (tokenType: string): void { + private emitTokenCase(tokenType: string): void { this.emitLine("case JsonToken.", tokenType, ":"); } - private emitThrow (message: Sourcelike): void { + private emitThrow(message: Sourcelike): void { this.emitLine("throw new Exception(", message, ");"); } - private deserializeTypeCode (typeName: Sourcelike): Sourcelike { + private deserializeTypeCode(typeName: Sourcelike): Sourcelike { return ["serializer.Deserialize<", typeName, ">(reader)"]; } - private serializeValueCode (value: Sourcelike): Sourcelike { + private serializeValueCode(value: Sourcelike): Sourcelike { return ["serializer.Serialize(writer, ", value, ")"]; } - private emitSerializeClass (): void { + private emitSerializeClass(): void { // FIXME: Make Serialize a Named this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { // Sometimes multiple top-levels will resolve to the same type, so we have to take care @@ -1050,39 +1042,39 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { seenTypes.add(t); this.emitExpressionMember( ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], - ["JsonConvert.SerializeObject(self, ", this._options.namespace, ".Converter.Settings)"], + ["JsonConvert.SerializeObject(self, ", this._options.namespace, ".Converter.Settings)"] ); } }); }); } - private emitCanConvert (expr: Sourcelike): void { + private emitCanConvert(expr: Sourcelike): void { this.emitExpressionMember("public override bool CanConvert(Type t)", expr); } - private emitReadJson (emitBody: () => void): void { + private emitReadJson(emitBody: () => void): void { this.emitLine( - "public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)", + "public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)" ); this.emitBlock(emitBody); } - private emitWriteJson (variable: string, emitBody: () => void): void { + private emitWriteJson(variable: string, emitBody: () => void): void { this.emitLine( "public override void WriteJson(JsonWriter writer, object ", variable, - ", JsonSerializer serializer)", + ", JsonSerializer serializer)" ); this.emitBlock(emitBody); } - private converterObject (converterName: Name): Sourcelike { + private converterObject(converterName: Name): Sourcelike { // FIXME: Get a singleton return [converterName, ".Singleton"]; } - private emitConverterClass (): void { + private emitConverterClass(): void { // FIXME: Make Converter a Named const converterName: Sourcelike = ["Converter"]; this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { @@ -1106,12 +1098,12 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { }); } - private emitDecoderTransformerCase ( + private emitDecoderTransformerCase( tokenCases: string[], variableName: string, xfer: Transformer | undefined, targetType: Type, - emitFinish: (value: Sourcelike) => void, + emitFinish: (value: Sourcelike) => void ): void { if (xfer === undefined) return; @@ -1127,11 +1119,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { }); } - private emitConsume ( + private emitConsume( value: Sourcelike, consumer: Transformer | undefined, targetType: Type, - emitFinish: (variableName: Sourcelike) => void, + emitFinish: (variableName: Sourcelike) => void ): boolean { if (consumer === undefined) { emitFinish(value); @@ -1141,11 +1133,11 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } } - private emitDecodeTransformer ( + private emitDecodeTransformer( xfer: Transformer, targetType: Type, emitFinish: (value: Sourcelike) => void, - variableName = "value", + variableName = "value" ): boolean { if (xfer instanceof DecodingTransformer) { const source = xfer.sourceType; @@ -1160,7 +1152,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { typeSource, ")converter.ReadJson(reader, typeof(", typeSource, - "), null, serializer);", + "), null, serializer);" ); } else if (source.kind !== "null") { let output = targetType.kind === "double" ? targetType : source; @@ -1183,7 +1175,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { xfer.itemTransformer, xfer.itemTargetType, v => this.emitLine(variableName, ".Add(", v, ");"), - "arrayItem", + "arrayItem" ); // FIXME: handle EOF this.emitLine("reader.Read();"); @@ -1213,14 +1205,14 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { "integerValue", xfer.integerTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( xfer.integerTransformer === undefined ? ["Integer", "Float"] : ["Float"], "doubleValue", xfer.doubleTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase(["Boolean"], "boolValue", xfer.boolTransformer, targetType, emitFinish); this.emitDecoderTransformerCase( @@ -1228,21 +1220,21 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { "stringValue", xfer.stringTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( ["StartObject"], "objectValue", xfer.objectTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( ["StartArray"], "arrayValue", xfer.arrayTransformer, targetType, - emitFinish, + emitFinish ); }); return false; @@ -1251,9 +1243,9 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } } - private stringCaseValue (t: Type, stringCase: string): Sourcelike { + private stringCaseValue(t: Type, stringCase: string): Sourcelike { if (t.kind === "string") { - return ["\"", utf16StringEscape(stringCase), "\""]; + return ['"', utf16StringEscape(stringCase), '"']; } else if (t instanceof EnumType) { return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; } @@ -1261,13 +1253,13 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return panic(`Type ${t.kind} does not have string cases`); } - private emitTransformer ( + private emitTransformer( variable: Sourcelike, xfer: Transformer, targetType: Type, - emitFinish: (value: Sourcelike) => void, + emitFinish: (value: Sourcelike) => void ): boolean { - function directTargetType (continuation: Transformer | undefined): Type { + function directTargetType(continuation: Transformer | undefined): Type { if (continuation === undefined) { return targetType; } @@ -1284,7 +1276,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const matchXfer = caseXfer as StringMatchTransformer; const value = this.stringCaseValue( followTargetType(matchXfer.sourceType), - matchXfer.stringCase, + matchXfer.stringCase ); this.emitLine("case ", value, ":"); this.indent(() => { @@ -1292,7 +1284,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { variable, matchXfer.transformer, targetType, - emitFinish, + emitFinish ); if (!allDone) { this.emitLine("break;"); @@ -1400,23 +1392,23 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { switch (xfer.sourceType.kind) { case "date-time": return this.emitConsume( - [variable, ".ToString(\"o\", System.Globalization.CultureInfo.InvariantCulture)"], + [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], xfer.consumer, targetType, - emitFinish, + emitFinish ); case "uuid": return this.emitConsume( - [variable, ".ToString(\"D\", System.Globalization.CultureInfo.InvariantCulture)"], + [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], xfer.consumer, targetType, - emitFinish, + emitFinish ); case "integer": case "uri": return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); case "bool": - this.emitLine("var boolString = ", variable, " ? \"true\" : \"false\";"); + this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); default: return panic(`Stringifying ${xfer.sourceType.kind} not supported`); @@ -1485,7 +1477,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { return false; } - private emitTransformation (converterName: Name, t: Type): void { + private emitTransformation(converterName: Name, t: Type): void { const xf = defined(transformationForType(t)); const reverse = xf.reverse; const targetType = xf.targetType; @@ -1513,7 +1505,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const allHandled = this.emitDecodeTransformer(xfer, targetType, v => this.emitLine("return ", v, ";")); if (!allHandled) { - this.emitThrow(["\"Cannot unmarshal type ", csType, "\""]); + this.emitThrow(['"Cannot unmarshal type ', csType, '"']); } }); this.ensureBlankLine(); @@ -1529,10 +1521,10 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.emitLine("var value = (", csType, ")untypedValue;"); const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;"), + this.emitLine("return;") ); if (!allHandled) { - this.emitThrow(["\"Cannot marshal type ", csType, "\""]); + this.emitThrow(['"Cannot marshal type ', csType, '"']); } }); this.ensureBlankLine(); @@ -1540,21 +1532,21 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { }); } - protected emitRequiredHelpers (): void { + protected emitRequiredHelpers(): void { if (this._needHelpers) { this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); this.ensureBlankLine(); this.emitSerializeClass(); } - if (this._needHelpers || this._needAttributes && (this.haveNamedUnions || this.haveEnums)) { + if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { this.ensureBlankLine(); this.emitConverterClass(); this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); } } - protected needNamespace (): boolean { + protected needNamespace(): boolean { return this._needNamespaces; } } @@ -1570,10 +1562,10 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { private readonly _needNamespaces: boolean; - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext, _options); this._needHelpers = _options.features.helpers; @@ -1581,7 +1573,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this._needNamespaces = _options.features.namespaces; } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { const forbidden = [ "Converter", "JsonConverter", @@ -1594,7 +1586,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // "MetadataPropertyHandling", // "DateParseHandling", "FromJson", - "Required", + "Required" ]; if (this._options.dense) { forbidden.push("J", "R", "N"); @@ -1607,13 +1599,13 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return super.forbiddenNamesForGlobalNamespace().concat(forbidden); } - protected forbiddenForObjectProperties (c: ClassType, className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { const result = super.forbiddenForObjectProperties(c, className); result.names = result.names.concat(["ToJson", "FromJson", "Required"]); return result; } - protected makeNameForTransformation (xf: Transformation, typeName: Name | undefined): Name { + protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { if (typeName === undefined) { let xfer = xf.transformer; if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { @@ -1626,19 +1618,19 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); } - protected makeNamedTypeDependencyNames (t: Type, name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { if (!(t instanceof EnumType)) return []; const extensionsName = new DependencyName( namingFunction, name.order + 30, - lookup => `${lookup(name)}_extensions`, + lookup => `${lookup(name)}_extensions` ); this._enumExtensionsNames.set(name, extensionsName); return [extensionsName]; } - protected emitUsings (): void { + protected emitUsings(): void { // FIXME: We need System.Collections.Generic whenever we have maps or use List. if (!this._needAttributes && !this._needHelpers) return; @@ -1660,11 +1652,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } } - protected baseclassForType (_t: Type): Sourcelike | undefined { + protected baseclassForType(_t: Type): Sourcelike | undefined { return this._options.baseclass; } - protected emitDefaultFollowingComments (): void { + protected emitDefaultFollowingComments(): void { if (!this._needHelpers) return; this.emitLine("#pragma warning restore CS8618"); @@ -1672,7 +1664,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitLine("#pragma warning restore CS8603"); } - protected emitDefaultLeadingComments (): void { + protected emitDefaultLeadingComments(): void { if (!this._needHelpers) return; this.emitLine("// "); @@ -1680,7 +1672,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitLine( "// To parse this JSON data, add NuGet 'System.Text.Json' then do", this.topLevels.size === 1 ? "" : " one of these", - ":", + ":" ); this.emitLine("//"); this.emitLine("// using ", this._options.namespace, ";"); @@ -1703,7 +1695,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitLine("#pragma warning disable CS8603"); } - private converterForType (t: Type): Name | undefined { + private converterForType(t: Type): Name | undefined { let xf = transformationForType(t); if (xf === undefined && t instanceof UnionType) { @@ -1721,11 +1713,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return defined(this.nameForTransformation(t)); } - protected attributesForProperty ( + protected attributesForProperty( property: ClassProperty, _name: Name, _c: ClassType, - jsonName: string, + jsonName: string ): Sourcelike[] | undefined { if (!this._needAttributes) return undefined; @@ -1754,7 +1746,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // required = [", Required = ", requiredClass, ".Always", nullValueHandling]; // } - attributes.push(["[", jsonPropertyName, "(\"", escapedName, "\")]"]); + attributes.push(["[", jsonPropertyName, '("', escapedName, '")]']); const converter = this.converterForType(property.type); if (converter !== undefined) { @@ -1764,16 +1756,16 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return attributes; } - protected blankLinesBetweenAttributes (): boolean { + protected blankLinesBetweenAttributes(): boolean { return this._needAttributes && !this._options.dense; } // The "this" type can't be `dynamic`, so we have to force it to `object`. - private topLevelResultType (t: Type): Sourcelike { + private topLevelResultType(t: Type): Sourcelike { return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); } - private emitFromJsonForTopLevel (t: Type, name: Name): void { + private emitFromJsonForTopLevel(t: Type, name: Name): void { if (t instanceof EnumType) return; let partial: string; @@ -1792,25 +1784,25 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // FIXME: Make FromJson a Named this.emitExpressionMember( ["public static ", csType, " FromJson(string json)"], - ["JsonSerializer.Deserialize<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"], + ["JsonSerializer.Deserialize<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] ); }); } - private emitDecoderSwitch (emitBody: () => void): void { + private emitDecoderSwitch(emitBody: () => void): void { this.emitLine("switch (reader.TokenType)"); this.emitBlock(emitBody); } - private emitTokenCase (tokenType: string): void { + private emitTokenCase(tokenType: string): void { this.emitLine("case JsonTokenType.", tokenType, ":"); } - private emitThrow (message: Sourcelike): void { + private emitThrow(message: Sourcelike): void { this.emitLine("throw new Exception(", message, ");"); } - private deserializeTypeCode (typeName: Sourcelike): Sourcelike { + private deserializeTypeCode(typeName: Sourcelike): Sourcelike { switch (typeName) { case "bool": return ["reader.GetBoolean()"]; @@ -1827,12 +1819,12 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } } - private serializeValueCode (value: Sourcelike): Sourcelike { + private serializeValueCode(value: Sourcelike): Sourcelike { if (value !== "null") return ["JsonSerializer.Serialize(writer, ", value, ", options)"]; else return ["writer.WriteNullValue()"]; } - private emitSerializeClass (): void { + private emitSerializeClass(): void { // FIXME: Make Serialize a Named this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { // Sometimes multiple top-levels will resolve to the same type, so we have to take care @@ -1844,49 +1836,49 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { seenTypes.add(t); this.emitExpressionMember( ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], - ["JsonSerializer.Serialize(self, ", this._options.namespace, ".Converter.Settings)"], + ["JsonSerializer.Serialize(self, ", this._options.namespace, ".Converter.Settings)"] ); } }); }); } - private emitCanConvert (expr: Sourcelike): void { + private emitCanConvert(expr: Sourcelike): void { this.emitExpressionMember("public override bool CanConvert(Type t)", expr); } - private emitReadJson (emitBody: () => void, csType: Sourcelike): void { + private emitReadJson(emitBody: () => void, csType: Sourcelike): void { this.emitLine( "public override ", csType, - " Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)", + " Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)" ); this.emitBlock(emitBody); } - private emitWriteJson (variable: string, emitBody: () => void, csType: Sourcelike): void { + private emitWriteJson(variable: string, emitBody: () => void, csType: Sourcelike): void { this.emitLine( "public override void Write(Utf8JsonWriter writer, ", csType, " ", variable, - ", JsonSerializerOptions options)", + ", JsonSerializerOptions options)" ); this.emitBlock(emitBody); } - private converterObject (converterName: Name): Sourcelike { + private converterObject(converterName: Name): Sourcelike { // FIXME: Get a singleton return [converterName, ".Singleton"]; } - private emitConverterClass (): void { + private emitConverterClass(): void { // FIXME: Make Converter a Named const converterName: Sourcelike = ["Converter"]; this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { // Do not use .Web as defaults. That turns on caseInsensitive property names and will fail the keywords test. this.emitLine( - "public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)", + "public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)" ); this.emitBlock(() => { // this.emitLine("MetadataPropertyHandling = MetadataPropertyHandling.Ignore,"); @@ -1910,12 +1902,12 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { }); } - private emitDecoderTransformerCase ( + private emitDecoderTransformerCase( tokenCases: string[], variableName: string, xfer: Transformer | undefined, targetType: Type, - emitFinish: (value: Sourcelike) => void, + emitFinish: (value: Sourcelike) => void ): void { if (xfer === undefined) return; @@ -1931,11 +1923,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { }); } - private emitConsume ( + private emitConsume( value: Sourcelike, consumer: Transformer | undefined, targetType: Type, - emitFinish: (variableName: Sourcelike) => void, + emitFinish: (variableName: Sourcelike) => void ): boolean { if (consumer === undefined) { emitFinish(value); @@ -1945,11 +1937,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } } - private emitDecodeTransformer ( + private emitDecodeTransformer( xfer: Transformer, targetType: Type, emitFinish: (value: Sourcelike) => void, - variableName = "value", + variableName = "value" ): boolean { if (xfer instanceof DecodingTransformer) { const source = xfer.sourceType; @@ -1964,7 +1956,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { typeSource, ")converter.ReadJson(reader, typeof(", typeSource, - "), null, serializer);", + "), null, serializer);" ); } else if (source.kind !== "null") { let output = targetType.kind === "double" ? targetType : source; @@ -1987,7 +1979,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { xfer.itemTransformer, xfer.itemTargetType, v => this.emitLine(variableName, ".Add(", v, ");"), - "arrayItem", + "arrayItem" ); // FIXME: handle EOF this.emitLine("reader.Read();"); @@ -2017,7 +2009,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { "integerValue", xfer.integerTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( ["Number"], @@ -2025,14 +2017,14 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { "doubleValue", xfer.doubleTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( ["True", "False"], "boolValue", xfer.boolTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( // ["String", "Date"], @@ -2040,21 +2032,21 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { "stringValue", xfer.stringTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( ["StartObject"], "objectValue", xfer.objectTransformer, targetType, - emitFinish, + emitFinish ); this.emitDecoderTransformerCase( ["StartArray"], "arrayValue", xfer.arrayTransformer, targetType, - emitFinish, + emitFinish ); }); return false; @@ -2063,9 +2055,9 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } } - private stringCaseValue (t: Type, stringCase: string): Sourcelike { + private stringCaseValue(t: Type, stringCase: string): Sourcelike { if (t.kind === "string") { - return ["\"", utf16StringEscape(stringCase), "\""]; + return ['"', utf16StringEscape(stringCase), '"']; } else if (t instanceof EnumType) { return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; } @@ -2073,13 +2065,13 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return panic(`Type ${t.kind} does not have string cases`); } - private emitTransformer ( + private emitTransformer( variable: Sourcelike, xfer: Transformer, targetType: Type, - emitFinish: (value: Sourcelike) => void, + emitFinish: (value: Sourcelike) => void ): boolean { - function directTargetType (continuation: Transformer | undefined): Type { + function directTargetType(continuation: Transformer | undefined): Type { if (continuation === undefined) { return targetType; } @@ -2096,7 +2088,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { const matchXfer = caseXfer as StringMatchTransformer; const value = this.stringCaseValue( followTargetType(matchXfer.sourceType), - matchXfer.stringCase, + matchXfer.stringCase ); this.emitLine("case ", value, ":"); this.indent(() => { @@ -2104,7 +2096,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { variable, matchXfer.transformer, targetType, - emitFinish, + emitFinish ); if (!allDone) { this.emitLine("break;"); @@ -2192,7 +2184,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.emitBlock(() => { // this.emitLine("var uri = new Uri(", variable, ");"); // The default value about:blank should never happen, but this way we avoid a null reference warning. - this.emitLine("var uri = new Uri(\"about:blank\");"); + this.emitLine('var uri = new Uri("about:blank");'); this.emitLine("if (!string.IsNullOrEmpty(stringValue))"); this.emitBlock(() => { this.emitLine("uri = new Uri(", variable, ");"); @@ -2218,23 +2210,23 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { switch (xfer.sourceType.kind) { case "date-time": return this.emitConsume( - [variable, ".ToString(\"o\", System.Globalization.CultureInfo.InvariantCulture)"], + [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], xfer.consumer, targetType, - emitFinish, + emitFinish ); case "uuid": return this.emitConsume( - [variable, ".ToString(\"D\", System.Globalization.CultureInfo.InvariantCulture)"], + [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], xfer.consumer, targetType, - emitFinish, + emitFinish ); case "integer": case "uri": return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); case "bool": - this.emitLine("var boolString = ", variable, " ? \"true\" : \"false\";"); + this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); default: return panic(`Stringifying ${xfer.sourceType.kind} not supported`); @@ -2303,7 +2295,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { return false; } - private emitTransformation (converterName: Name, t: Type): void { + private emitTransformation(converterName: Name, t: Type): void { const xf = defined(transformationForType(t)); const reverse = xf.reverse; const targetType = xf.targetType; @@ -2337,10 +2329,10 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // } const allHandled = this.emitDecodeTransformer(xfer, targetType, v => - this.emitLine("return ", v, ";"), + this.emitLine("return ", v, ";") ); if (!allHandled) { - this.emitThrow(["\"Cannot unmarshal type ", csType, "\""]); + this.emitThrow(['"Cannot unmarshal type ', csType, '"']); } }, csType); this.ensureBlankLine(); @@ -2357,28 +2349,28 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // } const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;"), + this.emitLine("return;") ); if (!allHandled) { - this.emitThrow(["\"Cannot marshal type ", csType, "\""]); + this.emitThrow(['"Cannot marshal type ', csType, '"']); } }, - csType, + csType ); this.ensureBlankLine(); this.emitLine("public static readonly ", converterName, " Singleton = new ", converterName, "();"); - }, + } ); } - protected emitRequiredHelpers (): void { + protected emitRequiredHelpers(): void { if (this._needHelpers) { this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); this.ensureBlankLine(); this.emitSerializeClass(); } - if (this._needHelpers || this._needAttributes && (this.haveNamedUnions || this.haveEnums)) { + if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { this.ensureBlankLine(); this.emitConverterClass(); this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); @@ -2495,7 +2487,7 @@ internal class IsoDateTimeOffsetConverter : JsonConverter } } - protected needNamespace (): boolean { + protected needNamespace(): boolean { return this._needNamespaces; } } diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts index 53d636499..d88b58060 100644 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ b/packages/quicktype-core/src/language/Kotlin.ts @@ -3,11 +3,11 @@ import { iterableSome, arrayIntercalate } from "collection-utils"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated, modifySource } from "../Source"; import { allLowerWordStyle, @@ -23,31 +23,21 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap, + utf32ConcatMap } from "../support/Strings"; import { assertNever, mustNotHappen } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { - type ClassProperty, - type EnumType, - type ObjectType, - type PrimitiveType, - type Type} from "../Type"; -import { - ArrayType, - ClassType, - MapType, - UnionType, -} from "../Type"; +import { type ClassProperty, type EnumType, type ObjectType, type PrimitiveType, type Type } from "../Type"; +import { ArrayType, ClassType, MapType, UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; import { type RenderContext } from "../Renderer"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; export enum Framework { - None, - Jackson, - Klaxon, - KotlinX + None = "None", + Jackson = "Jackson", + Klaxon = "Klaxon", + KotlinX = "KotlinX" } export const kotlinOptions = { @@ -58,34 +48,34 @@ export const kotlinOptions = { ["just-types", Framework.None], ["jackson", Framework.Jackson], ["klaxon", Framework.Klaxon], - ["kotlinx", Framework.KotlinX], + ["kotlinx", Framework.KotlinX] ], - "klaxon", + "klaxon" ), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") }; export class KotlinTargetLanguage extends TargetLanguage { - constructor () { + constructor() { super("Kotlin", ["kotlin"], "kt"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [kotlinOptions.framework, kotlinOptions.acronymStyle, kotlinOptions.packageName]; } - get supportsOptionalClassProperties (): boolean { + get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes (): boolean { + get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): ConvenienceRenderer { const options = getOptionValues(kotlinOptions, untypedOptionValues); @@ -153,23 +143,23 @@ const keywords = [ "JsonObject", "JsonValue", "Converter", - "Klaxon", + "Klaxon" ]; -function isPartCharacter (codePoint: number): boolean { +function isPartCharacter(codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter (codePoint: number): boolean { +function isStartCharacter(codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function kotlinNameStyle ( +function kotlinNameStyle( isUpper: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle, + acronymsStyle: (s: string) => string = allUpperWordStyle ): string { const words = splitIntoWords(original); return combineWords( @@ -180,92 +170,92 @@ function kotlinNameStyle ( isUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, "", - isStartCharacter, + isStartCharacter ); } -function unicodeEscape (codePoint: number): string { +function unicodeEscape(codePoint: number): string { return "\\u" + intToHex(codePoint, 4); } const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); -function stringEscape (s: string): string { +function stringEscape(s: string): string { // "$this" is a template string in Kotlin so we have to escape $ return _stringEscape(s).replace(/\$/g, "\\$"); } export class KotlinRenderer extends ConvenienceRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _kotlinOptions: OptionValues, + protected readonly _kotlinOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords; } - protected forbiddenForObjectProperties (_o: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_o: ObjectType, _classNamed: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected topLevelNameStyle (rawName: string): string { + protected topLevelNameStyle(rawName: string): string { return kotlinNameStyle(true, rawName); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return funPrefixNamer("lower", s => kotlinNameStyle(false, s, acronymStyle(this._kotlinOptions.acronymStyle))); } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return funPrefixNamer("upper", s => kotlinNameStyle(true, s) + "Value"); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock (line: Sourcelike, f: () => void, delimiter: "curly" | "paren" | "lambda" = "curly"): void { + protected emitBlock(line: Sourcelike, f: () => void, delimiter: "curly" | "paren" | "lambda" = "curly"): void { const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" ? ["(", ")"] : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); } - protected anySourceType (optional: string): Sourcelike { + protected anySourceType(optional: string): Sourcelike { return ["Any", optional]; } // (asarazan): I've broken out the following two functions // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType (arrayType: ArrayType, withIssues = false, _noOptional = false): Sourcelike { + protected arrayType(arrayType: ArrayType, withIssues = false, _noOptional = false): Sourcelike { return ["List<", this.kotlinType(arrayType.items, withIssues), ">"]; } - protected mapType (mapType: MapType, withIssues = false, _noOptional = false): Sourcelike { + protected mapType(mapType: MapType, withIssues = false, _noOptional = false): Sourcelike { return ["Map"]; } - protected kotlinType (t: Type, withIssues = false, noOptional = false): Sourcelike { + protected kotlinType(t: Type, withIssues = false, noOptional = false): Sourcelike { const optional = noOptional ? "" : "?"; return matchType( t, @@ -287,15 +277,15 @@ export class KotlinRenderer extends ConvenienceRenderer { const nullable = nullableFromUnion(unionType); if (nullable !== null) return [this.kotlinType(nullable, withIssues), optional]; return this.nameForNamedType(unionType); - }, + } ); } - protected emitUsageHeader (): void { + protected emitUsageHeader(): void { // To be overridden } - protected emitHeader (): void { + protected emitHeader(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -307,23 +297,23 @@ export class KotlinRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitLine(["typealias ", name, " = ArrayList<", elementType, ">"]); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); this.emitLine(["typealias ", name, " = HashMap"]); } - protected emitEmptyClassDefinition (c: ClassType, className: Name): void { + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitClassAnnotations(c, className); this.emitLine("class ", className, "()"); } - protected emitClassDefinition (c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name): void { if (c.getProperties().size === 0) { this.emitEmptyClassDefinition(c, className); return; @@ -377,19 +367,19 @@ export class KotlinRenderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(c, className); } - protected emitClassDefinitionMethods (_c: ClassType, _className: Name) { + protected emitClassDefinitionMethods(_c: ClassType, _className: Name) { this.emitLine(")"); } - protected emitClassAnnotations (_c: Type, _className: Name) { + protected emitClassAnnotations(_c: Type, _className: Name) { // to be overridden } - protected renameAttribute (_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>) { + protected renameAttribute(_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>) { // to be overridden } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["enum class ", enumName], () => { @@ -400,8 +390,8 @@ export class KotlinRenderer extends ConvenienceRenderer { }); } - protected emitUnionDefinition (u: UnionType, unionName: Name): void { - function sortBy (t: Type): string { + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -417,13 +407,13 @@ export class KotlinRenderer extends ConvenienceRenderer { this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { table.push([ ["class ", name, "(val value: ", this.kotlinType(t), ")"], - [" : ", unionName, "()"], + [" : ", unionName, "()"] ]); }); if (maybeNull !== null) { table.push([ ["class ", this.nameForUnionMember(u, maybeNull), "()"], - [" : ", unionName, "()"], + [" : ", unionName, "()"] ]); } @@ -434,16 +424,16 @@ export class KotlinRenderer extends ConvenienceRenderer { }); } - protected emitUnionDefinitionMethods ( + protected emitUnionDefinitionMethods( _u: UnionType, _nonNulls: ReadonlySet, _maybeNull: PrimitiveType | null, - _unionName: Name, + _unionName: Name ) { // to be overridden } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.emitHeader(); // Top-level arrays, maps @@ -459,21 +449,21 @@ export class KotlinRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n), + (u, n) => this.emitUnionDefinition(u, n) ); } } export class KotlinKlaxonRenderer extends KotlinRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues, + _kotlinOptions: OptionValues ) { super(targetLanguage, renderContext, _kotlinOptions); } - private unionMemberFromJsonValue (t: Type, e: Sourcelike): Sourcelike { + private unionMemberFromJsonValue(t: Type, e: Sourcelike): Sourcelike { return matchType( t, _anyType => [e, ".inside"], @@ -486,11 +476,11 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { _classType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], _mapType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], enumType => [e, ".string?.let { ", this.kotlinType(enumType), ".fromValue(it) }"], - _unionType => mustNotHappen(), + _unionType => mustNotHappen() ); } - private unionMemberJsonValueGuard (t: Type, _e: Sourcelike): Sourcelike { + private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { return matchType( t, _anyType => "is Any", @@ -507,11 +497,11 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { // This could be stricter, but for now we don't allow strings // and enums in the same union _enumType => "is String", - _unionType => mustNotHappen(), + _unionType => mustNotHappen() ); } - protected emitUsageHeader (): void { + protected emitUsageHeader(): void { this.emitLine("// To parse the JSON, install Klaxon and do:"); this.emitLine("//"); this.forEachTopLevel("none", (_, name) => { @@ -519,18 +509,18 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { }); } - protected emitHeader (): void { + protected emitHeader(): void { super.emitHeader(); this.emitLine("import com.beust.klaxon.*"); const hasUnions = iterableSome( this.typeGraph.allNamedTypes(), - t => t instanceof UnionType && nullableFromUnion(t) === null, + t => t instanceof UnionType && nullableFromUnion(t) === null ); const hasEmptyObjects = iterableSome( this.typeGraph.allNamedTypes(), - c => c instanceof ClassType && c.getProperties().size === 0, + c => c instanceof ClassType && c.getProperties().size === 0 ); if (hasUnions || this.haveEnums || hasEmptyObjects) { this.emitGenericConverter(); @@ -545,14 +535,14 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { converters.push([ [".convert(", name, "::class,"], [" { ", name, ".fromValue(it.string!!) },"], - [" { \"\\\"${it.value}\\\"\" })"], + [' { "\\"${it.value}\\"" })'] ]); }); this.forEachUnion("none", (_, name) => { converters.push([ [".convert(", name, "::class,"], [" { ", name, ".fromJson(it) },"], - [" { it.toJson() }, true)"], + [" { it.toJson() }, true)"] ]); }); @@ -563,7 +553,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitBlock( ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], @@ -576,14 +566,14 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { name, "(klaxon.parseArray<", elementType, - ">(json)!!)", + ">(json)!!)" ); }); - }, + } ); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); this.emitBlock( [ @@ -593,7 +583,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { elementType, ">) : HashMap(elements)", + ">(elements)" ], () => { this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); @@ -605,22 +595,22 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { this.emitLine( "klaxon.parseJsonObject(java.io.StringReader(json)) as Map", + ">" ); }, - "paren", + "paren" ); }); - }, + } ); } - private klaxonRenameAttribute (propName: Name, jsonName: string, ignore = false): Sourcelike | undefined { + private klaxonRenameAttribute(propName: Name, jsonName: string, ignore = false): Sourcelike | undefined { const escapedName = stringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; const properties: Sourcelike[] = []; if (namesDiffer) { - properties.push(["name = \"", escapedName, "\""]); + properties.push(['name = "', escapedName, '"']); } if (ignore) { @@ -630,13 +620,13 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { return properties.length === 0 ? undefined : ["@Json(", arrayIntercalate(", ", properties), ")"]; } - protected emitEmptyClassDefinition (c: ClassType, className: Name): void { + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("typealias ", className, " = JsonObject"); } - protected emitClassDefinitionMethods (c: ClassType, className: Name) { + protected emitClassDefinitionMethods(c: ClassType, className: Name) { const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); if (isTopLevel) { this.emitBlock(")", () => { @@ -651,14 +641,14 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } } - protected renameAttribute (name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { + protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { const rename = this.klaxonRenameAttribute(name, jsonName); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); } } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { @@ -680,33 +670,33 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { }); } - private emitGenericConverter (): void { + private emitGenericConverter(): void { this.ensureBlankLine(); this.emitLine( - "private fun Klaxon.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonValue) -> T, toJson: (T) -> String, isUnion: Boolean = false) =", + "private fun Klaxon.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonValue) -> T, toJson: (T) -> String, isUnion: Boolean = false) =" ); this.indent(() => { this.emitLine("this.converter(object: Converter {"); this.indent(() => { - this.emitLine("@Suppress(\"UNCHECKED_CAST\")"); + this.emitLine('@Suppress("UNCHECKED_CAST")'); this.emitTable([ ["override fun toJson(value: Any)", " = toJson(value as T)"], ["override fun fromJson(jv: JsonValue)", " = fromJson(jv) as Any"], [ "override fun canConvert(cls: Class<*>)", - " = cls == k.java || (isUnion && cls.superclass == k.java)", - ], + " = cls == k.java || (isUnion && cls.superclass == k.java)" + ] ]); }); this.emitLine("})"); }); } - protected emitUnionDefinitionMethods ( + protected emitUnionDefinitionMethods( u: UnionType, nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, - unionName: Name, + unionName: Name ) { this.ensureBlankLine(); this.emitLine("public fun toJson(): String = klaxon.toJsonString(when (this) {"); @@ -717,7 +707,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { }); if (maybeNull !== null) { const name = this.nameForUnionMember(u, maybeNull); - toJsonTable.push([["is ", name], [" -> \"null\""]]); + toJsonTable.push([["is ", name], [' -> "null"']]); } this.emitTable(toJsonTable); @@ -731,7 +721,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { table.push([ [this.unionMemberJsonValueGuard(t, "jv.inside")], - [" -> ", name, "(", this.unionMemberFromJsonValue(t, "jv"), "!!)"], + [" -> ", name, "(", this.unionMemberFromJsonValue(t, "jv"), "!!)"] ]); }); if (maybeNull !== null) { @@ -748,15 +738,15 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } export class KotlinJacksonRenderer extends KotlinRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues, + _kotlinOptions: OptionValues ) { super(targetLanguage, renderContext, _kotlinOptions); } - private unionMemberJsonValueGuard (t: Type, _e: Sourcelike): Sourcelike { + private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { return matchType( t, _anyType => "is Any", @@ -773,11 +763,11 @@ export class KotlinJacksonRenderer extends KotlinRenderer { // This could be stricter, but for now we don't allow strings // and enums in the same union _enumType => "is TextNode", - _unionType => mustNotHappen(), + _unionType => mustNotHappen() ); } - protected emitUsageHeader (): void { + protected emitUsageHeader(): void { this.emitLine("// To parse the JSON, install jackson-module-kotlin and do:"); this.emitLine("//"); this.forEachTopLevel("none", (_, name) => { @@ -785,7 +775,7 @@ export class KotlinJacksonRenderer extends KotlinRenderer { }); } - protected emitHeader (): void { + protected emitHeader(): void { super.emitHeader(); this.emitMultiline(`import com.fasterxml.jackson.annotation.* @@ -799,11 +789,11 @@ import com.fasterxml.jackson.module.kotlin.*`); const hasUnions = iterableSome( this.typeGraph.allNamedTypes(), - t => t instanceof UnionType && nullableFromUnion(t) === null, + t => t instanceof UnionType && nullableFromUnion(t) === null ); const hasEmptyObjects = iterableSome( this.typeGraph.allNamedTypes(), - c => c instanceof ClassType && c.getProperties().size === 0, + c => c instanceof ClassType && c.getProperties().size === 0 ); if (hasUnions || this.haveEnums || hasEmptyObjects) { this.emitGenericConverter(); @@ -817,14 +807,14 @@ import com.fasterxml.jackson.module.kotlin.*`); converters.push([ ["convert(", name, "::class,"], [" { ", name, ".fromValue(it.asText()) },"], - [" { \"\\\"${it.value}\\\"\" })"], + [' { "\\"${it.value}\\"" })'] ]); }); this.forEachUnion("none", (_, name) => { converters.push([ ["convert(", name, "::class,"], [" { ", name, ".fromJson(it) },"], - [" { it.toJson() }, true)"], + [" { it.toJson() }, true)"] ]); }); @@ -842,7 +832,7 @@ import com.fasterxml.jackson.module.kotlin.*`); this.emitLine("}"); } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitBlock( ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], @@ -852,11 +842,11 @@ import com.fasterxml.jackson.module.kotlin.*`); this.emitBlock("companion object", () => { this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); }); - }, + } ); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); this.emitBlock( [ @@ -866,7 +856,7 @@ import com.fasterxml.jackson.module.kotlin.*`); elementType, ">) : HashMap(elements)", + ">(elements)" ], () => { this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); @@ -874,15 +864,15 @@ import com.fasterxml.jackson.module.kotlin.*`); this.emitBlock("companion object", () => { this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); }); - }, + } ); } - private jacksonRenameAttribute ( + private jacksonRenameAttribute( propName: Name, jsonName: string, required: boolean, - ignore = false, + ignore = false ): Sourcelike | undefined { const escapedName = stringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; @@ -891,7 +881,7 @@ import com.fasterxml.jackson.module.kotlin.*`); const propertyOpts: Sourcelike[] = []; if (namesDiffer || isPrefixBool) { - propertyOpts.push("\"" + escapedName + "\""); + propertyOpts.push('"' + escapedName + '"'); } if (required) { @@ -911,13 +901,13 @@ import com.fasterxml.jackson.module.kotlin.*`); return properties.length === 0 ? undefined : properties; } - protected emitEmptyClassDefinition (c: ClassType, className: Name): void { + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("typealias ", className, " = JsonNode"); } - protected emitClassDefinitionMethods (c: ClassType, className: Name) { + protected emitClassDefinitionMethods(c: ClassType, className: Name) { const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); if (isTopLevel) { this.emitBlock(")", () => { @@ -932,14 +922,14 @@ import com.fasterxml.jackson.module.kotlin.*`); } } - protected renameAttribute (name: Name, jsonName: string, required: boolean, meta: Array<() => void>) { + protected renameAttribute(name: Name, jsonName: string, required: boolean, meta: Array<() => void>) { const rename = this.jacksonRenameAttribute(name, jsonName, required); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); } } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { @@ -961,7 +951,7 @@ import com.fasterxml.jackson.module.kotlin.*`); }); } - private emitGenericConverter (): void { + private emitGenericConverter(): void { this.ensureBlankLine(); this.emitMultiline(` @Suppress("UNCHECKED_CAST") @@ -975,11 +965,11 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso })`); } - protected emitUnionDefinitionMethods ( + protected emitUnionDefinitionMethods( u: UnionType, nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, - unionName: Name, + unionName: Name ) { this.ensureBlankLine(); this.emitLine("fun toJson(): String = mapper.writeValueAsString(when (this) {"); @@ -990,7 +980,7 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso }); if (maybeNull !== null) { const name = this.nameForUnionMember(u, maybeNull); - toJsonTable.push([["is ", name], [" -> \"null\""]]); + toJsonTable.push([["is ", name], [' -> "null"']]); } this.emitTable(toJsonTable); @@ -1022,19 +1012,19 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso * TODO: Union, Any, Top Level Array, Top Level Map */ export class KotlinXRenderer extends KotlinRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues, + _kotlinOptions: OptionValues ) { super(targetLanguage, renderContext, _kotlinOptions); } - protected anySourceType (optional: string): Sourcelike { + protected anySourceType(optional: string): Sourcelike { return ["JsonElement", optional]; } - protected arrayType (arrayType: ArrayType, withIssues = false, noOptional = false): Sourcelike { + protected arrayType(arrayType: ArrayType, withIssues = false, noOptional = false): Sourcelike { const valType = this.kotlinType(arrayType.items, withIssues, true); const name = this.sourcelikeToString(valType); if (name === "JsonObject" || name === "JsonElement") { @@ -1044,7 +1034,7 @@ export class KotlinXRenderer extends KotlinRenderer { return super.arrayType(arrayType, withIssues, noOptional); } - protected mapType (mapType: MapType, withIssues = false, noOptional = false): Sourcelike { + protected mapType(mapType: MapType, withIssues = false, noOptional = false): Sourcelike { const valType = this.kotlinType(mapType.values, withIssues, true); const name = this.sourcelikeToString(valType); if (name === "JsonObject" || name === "JsonElement") { @@ -1054,7 +1044,7 @@ export class KotlinXRenderer extends KotlinRenderer { return super.mapType(mapType, withIssues, noOptional); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); if (elementType === "JsonObject") { this.emitLine(["typealias ", name, " = JsonObject"]); @@ -1063,12 +1053,12 @@ export class KotlinXRenderer extends KotlinRenderer { } } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitLine(["typealias ", name, " = JsonArray<", elementType, ">"]); } - protected emitUsageHeader (): void { + protected emitUsageHeader(): void { this.emitLine("// To parse the JSON, install kotlin's serialization plugin and do:"); this.emitLine("//"); const table: Sourcelike[][] = []; @@ -1077,13 +1067,13 @@ export class KotlinXRenderer extends KotlinRenderer { table.push([ "// val ", modifySource(camelCase, name), - ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)`, + ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)` ]); }); this.emitTable(table); } - protected emitHeader (): void { + protected emitHeader(): void { super.emitHeader(); this.emitLine("import kotlinx.serialization.*"); @@ -1092,28 +1082,28 @@ export class KotlinXRenderer extends KotlinRenderer { this.emitLine("import kotlinx.serialization.encoding.*"); } - protected emitClassAnnotations (_c: Type, _className: Name) { + protected emitClassAnnotations(_c: Type, _className: Name) { this.emitLine("@Serializable"); } - protected renameAttribute (name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { + protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { const rename = this._rename(name, jsonName); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); } } - private _rename (propName: Name, jsonName: string): Sourcelike | undefined { + private _rename(propName: Name, jsonName: string): Sourcelike | undefined { const escapedName = stringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; if (namesDiffer) { - return ["@SerialName(\"", escapedName, "\")"]; + return ['@SerialName("', escapedName, '")']; } return undefined; } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine(["@Serializable"]); diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust.ts index b09b1dc7f..fe5941cdc 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust.ts @@ -15,14 +15,14 @@ import { escapeNonPrintableMapper, isPrintable, isAscii, - isLetterOrUnderscore, + isLetterOrUnderscore } from "../support/Strings"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { type Type, type ClassType, type EnumType } from "../Type"; import { UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type Option, type OptionValues } from "../RendererOptions"; @@ -31,32 +31,32 @@ import { defined } from "../support/Support"; import { type RenderContext } from "../Renderer"; export enum Density { - Normal, - Dense + Normal = "Normal", + Dense = "Dense" } export enum Visibility { - Private, - Crate, - Public + Private = "Private", + Crate = "Crate", + Public = "Public" } export const rustOptions = { density: new EnumOption("density", "Density", [ ["normal", Density.Normal], - ["dense", Density.Dense], + ["dense", Density.Dense] ]), visibility: new EnumOption("visibility", "Field visibility", [ ["private", Visibility.Private], ["crate", Visibility.Crate], - ["public", Visibility.Public], + ["public", Visibility.Public] ]), deriveDebug: new BooleanOption("derive-debug", "Derive Debug impl", false), deriveClone: new BooleanOption("derive-clone", "Derive Clone impl", false), derivePartialEq: new BooleanOption("derive-partial-eq", "Derive PartialEq impl", false), skipSerializingNone: new BooleanOption("skip-serializing-none", "Skip serializing empty Option fields", false), edition2018: new BooleanOption("edition-2018", "Edition 2018", true), - leadingComments: new BooleanOption("leading-comments", "Leading Comments", true), + leadingComments: new BooleanOption("leading-comments", "Leading Comments", true) }; type NameToParts = (name: string) => string[]; @@ -71,12 +71,12 @@ const namingStyles: Record = { snake_case: { regex: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/, toParts: (name: string): string[] => name.split("_"), - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("_"), + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("_") }, SCREAMING_SNAKE_CASE: { regex: /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/, toParts: (name: string): string[] => name.split("_"), - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("_"), + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("_") }, camelCase: { regex: /^[a-z]+([A-Z0-9][a-z]*)*$/, @@ -84,48 +84,48 @@ const namingStyles: Record = { fromParts: (parts: string[]): string => parts .map((p, i) => - i === 0 ? p.toLowerCase() : p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase(), + i === 0 ? p.toLowerCase() : p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase() ) - .join(""), + .join("") }, PascalCase: { regex: /^[A-Z][a-z]*([A-Z0-9][a-z]*)*$/, toParts: (name: string): string[] => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")), fromParts: (parts: string[]): string => - parts.map(p => p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase()).join(""), + parts.map(p => p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase()).join("") }, "kebab-case": { regex: /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/, toParts: (name: string): string[] => name.split("-"), - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("-"), + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("-") }, "SCREAMING-KEBAB-CASE": { regex: /^[A-Z][A-Z0-9]*(-[A-Z0-9]+)*$/, toParts: (name: string): string[] => name.split("-"), - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("-"), + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("-") }, lowercase: { regex: /^[a-z][a-z0-9]*$/, toParts: (name: string): string[] => [name], - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join(""), + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("") }, UPPERCASE: { regex: /^[A-Z][A-Z0-9]*$/, toParts: (name: string): string[] => [name], - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join(""), - }, + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("") + } }; export class RustTargetLanguage extends TargetLanguage { - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): RustRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): RustRenderer { return new RustRenderer(this, renderContext, getOptionValues(rustOptions, untypedOptionValues)); } - constructor () { + constructor() { super("Rust", ["rust", "rs", "rustlang"], "rs"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ rustOptions.density, rustOptions.visibility, @@ -134,7 +134,7 @@ export class RustTargetLanguage extends TargetLanguage { rustOptions.derivePartialEq, rustOptions.edition2018, rustOptions.leadingComments, - rustOptions.skipSerializingNone, + rustOptions.skipSerializingNone ]; } } @@ -213,7 +213,7 @@ const keywords = [ "union", // Conflict between `std::Option` and potentially generated Option - "option", + "option" ]; const isAsciiLetterOrUnderscoreOrDigit = (codePoint: number): boolean => { @@ -234,7 +234,7 @@ const isAsciiLetterOrUnderscore = (codePoint: number): boolean => { const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); -function rustStyle (original: string, isSnakeCase: boolean): string { +function rustStyle(original: string, isSnakeCase: boolean): string { const words = splitIntoWords(original); const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; @@ -247,7 +247,7 @@ function rustStyle (original: string, isSnakeCase: boolean): string { wordStyle, wordStyle, isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore, + isAsciiLetterOrUnderscore ); return combined === "_" ? "_underscore" : combined; @@ -267,60 +267,60 @@ const standardUnicodeRustEscape = (codePoint: number): string => { const rustStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeRustEscape)); export class RustRenderer extends ConvenienceRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return camelNamingFunction; } - protected namerForObjectProperty (): Namer | null { + protected namerForObjectProperty(): Namer | null { return snakeNamingFunction; } - protected makeUnionMemberNamer (): Namer | null { + protected makeUnionMemberNamer(): Namer | null { return camelNamingFunction; } - protected makeEnumCaseNamer (): Namer | null { + protected makeEnumCaseNamer(): Namer | null { return camelNamingFunction; } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected get commentLineStart (): string { + protected get commentLineStart(): string { return "/// "; } - private nullableRustType (t: Type, withIssues: boolean): Sourcelike { + private nullableRustType(t: Type, withIssues: boolean): Sourcelike { return ["Option<", this.breakCycle(t, withIssues), ">"]; } - protected isImplicitCycleBreaker (t: Type): boolean { + protected isImplicitCycleBreaker(t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } - private rustType (t: Type, withIssues = false): Sourcelike { + private rustType(t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "Option"), @@ -347,40 +347,40 @@ export class RustRenderer extends ConvenienceRenderer { : this.nameForNamedType(unionType); return hasNull !== null ? (["Option<", name, ">"] as Sourcelike) : name; - }, + } ); } - private breakCycle (t: Type, withIssues: boolean): any { + private breakCycle(t: Type, withIssues: boolean): any { const rustType = this.rustType(t, withIssues); const isCycleBreaker = this.isCycleBreakerType(t); return isCycleBreaker ? ["Box<", rustType, ">"] : rustType; } - private emitRenameAttribute ( + private emitRenameAttribute( propName: Name, jsonName: string, defaultNamingStyle: string, - preferedNamingStyle: string, + preferedNamingStyle: string ) { const escapedName = rustStringEscape(jsonName); const name = namingStyles[defaultNamingStyle].fromParts(this.sourcelikeToString(propName).split(" ")); const styledName = nameToNamingStyle(name, preferedNamingStyle); const namesDiffer = escapedName !== styledName; if (namesDiffer) { - this.emitLine("#[serde(rename = \"", escapedName, "\")]"); + this.emitLine('#[serde(rename = "', escapedName, '")]'); } } - private emitSkipSerializeNone (t: Type) { + private emitSkipSerializeNone(t: Type) { if (t instanceof UnionType) { const nullable = nullableFromUnion(t); - if (nullable !== null) this.emitLine("#[serde(skip_serializing_if = \"Option::is_none\")]"); + if (nullable !== null) this.emitLine('#[serde(skip_serializing_if = "Option::is_none")]'); } } - private get visibility (): string { + private get visibility(): string { if (this._options.visibility === Visibility.Crate) { return "pub(crate) "; } else if (this._options.visibility === Visibility.Public) { @@ -390,18 +390,18 @@ export class RustRenderer extends ConvenienceRenderer { return ""; } - protected emitStructDefinition (c: ClassType, className: Name): void { + protected emitStructDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine( "#[derive(", this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", this._options.derivePartialEq ? "PartialEq, " : "", - "Serialize, Deserialize)]", + "Serialize, Deserialize)]" ); // List the possible naming styles for every class property - const propertiesNamingStyles: { [key: string]: string[], } = {}; + const propertiesNamingStyles: { [key: string]: string[] } = {}; this.forEachClassProperty(c, "none", (_name, jsonName, _prop) => { propertiesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName); }); @@ -425,13 +425,13 @@ export class RustRenderer extends ConvenienceRenderer { this.emitBlock(["pub struct ", className], structBody); } - protected emitBlock (line: Sourcelike, f: () => void): void { + protected emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected emitUnion (u: UnionType, unionName: Name): void { + protected emitUnion(u: UnionType, unionName: Name): void { const isMaybeWithSingleType = nullableFromUnion(u); if (isMaybeWithSingleType !== null) { @@ -444,7 +444,7 @@ export class RustRenderer extends ConvenienceRenderer { this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", this._options.derivePartialEq ? "PartialEq, " : "", - "Serialize, Deserialize)]", + "Serialize, Deserialize)]" ); this.emitLine("#[serde(untagged)]"); @@ -455,22 +455,22 @@ export class RustRenderer extends ConvenienceRenderer { this.forEachUnionMember(u, nonNulls, blankLines, null, (fieldName, t) => { const rustType = this.breakCycle(t, true); this.emitLine([fieldName, "(", rustType, "),"]); - }), + }) ); } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine( "#[derive(", this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", this._options.derivePartialEq ? "PartialEq, " : "", - "Serialize, Deserialize)]", + "Serialize, Deserialize)]" ); // List the possible naming styles for every enum case - const enumCasesNamingStyles: { [key: string]: string[], } = {}; + const enumCasesNamingStyles: { [key: string]: string[] } = {}; this.forEachEnumCase(e, "none", (_name, jsonName) => { enumCasesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName); }); @@ -487,15 +487,15 @@ export class RustRenderer extends ConvenienceRenderer { this.forEachEnumCase(e, blankLines, (name, jsonName) => { this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle); this.emitLine([name, ","]); - }), + }) ); } - protected emitTopLevelAlias (t: Type, name: Name): void { + protected emitTopLevelAlias(t: Type, name: Name): void { this.emitLine("pub type ", name, " = ", this.rustType(t), ";"); } - protected emitLeadingComments (): void { + protected emitLeadingComments(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); return; @@ -514,11 +514,11 @@ export class RustRenderer extends ConvenienceRenderer { // fn main() { // let json = r#"{"answer": 42}"#; // let model: ${topLevelName} = serde_json::from_str(&json).unwrap(); -// }`, +// }` ); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { if (this._options.leadingComments) { this.emitLeadingComments(); } @@ -537,19 +537,19 @@ export class RustRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading", (t, name) => this.emitTopLevelAlias(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, name: Name) => this.emitStructDefinition(c, name), (e, name) => this.emitEnumDefinition(e, name), - (u, name) => this.emitUnion(u, name), + (u, name) => this.emitUnion(u, name) ); } } -function getPreferedNamingStyle (namingStyleOccurences: string[], defaultStyle: string): string { +function getPreferedNamingStyle(namingStyleOccurences: string[], defaultStyle: string): string { const occurrences = Object.fromEntries(Object.keys(namingStyles).map(key => [key, 0])); namingStyleOccurences.forEach(style => ++occurrences[style]); const max = Math.max(...Object.values(occurrences)); @@ -563,13 +563,13 @@ function getPreferedNamingStyle (namingStyleOccurences: string[], defaultStyle: return preferedStyles[0]; } -function listMatchingNamingStyles (name: string): string[] { +function listMatchingNamingStyles(name: string): string[] { return Object.entries(namingStyles) .filter(([_, { regex }]) => regex.test(name)) .map(([namingStyle, _]) => namingStyle); } -function nameToNamingStyle (name: string, style: string): string { +function nameToNamingStyle(name: string, style: string): string { if (namingStyles[style].regex.test(name)) { return name; } diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts index 3d93c0343..c173aed7c 100644 --- a/packages/quicktype-core/src/language/Scala3.ts +++ b/packages/quicktype-core/src/language/Scala3.ts @@ -1,11 +1,11 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated } from "../Source"; import { allLowerWordStyle, @@ -16,7 +16,7 @@ import { isLetterOrUnderscore, isNumeric, legalizeCharacters, - splitIntoWords, + splitIntoWords } from "../support/Strings"; import { assertNever } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; @@ -26,9 +26,9 @@ import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils" import { type RenderContext } from "../Renderer"; export enum Framework { - None, - Upickle, - Circe + None = "None", + Upickle = "Upickle", + Circe = "Circe" } export const scala3Options = { @@ -38,11 +38,11 @@ export const scala3Options = { [ ["just-types", Framework.None], ["circe", Framework.Circe], - ["upickle", Framework.Upickle], + ["upickle", Framework.Upickle] ], - undefined, + undefined ), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") }; // Use backticks for param names with symbols @@ -65,13 +65,13 @@ const invalidSymbols = [ "/", ";", "'", - "\"", + '"', "{", "}", ":", "~", "`", - ".", + "." ]; const keywords = [ @@ -130,7 +130,7 @@ const keywords = [ "Array", "List", "Map", - "Enum", + "Enum" ]; /** @@ -154,17 +154,17 @@ const wrapOption = (s: string, optional: boolean): string => { } }; -function isPartCharacter (codePoint: number): boolean { +function isPartCharacter(codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter (codePoint: number): boolean { +function isStartCharacter(codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function scalaNameStyle (isUpper: boolean, original: string): string { +function scalaNameStyle(isUpper: boolean, original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -174,7 +174,7 @@ function scalaNameStyle (isUpper: boolean, original: string): string { isUpper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter, + isStartCharacter ); } @@ -193,87 +193,87 @@ const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s) const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); export class Scala3Renderer extends ConvenienceRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _scalaOptions: OptionValues, + protected readonly _scalaOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords; } - protected forbiddenForObjectProperties (_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected topLevelNameStyle (rawName: string): string { + protected topLevelNameStyle(rawName: string): string { return scalaNameStyle(true, rawName); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return upperNamingFunction; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return lowerNamingFunction; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock ( + protected emitBlock( line: Sourcelike, f: () => void, - delimiter: "curly" | "paren" | "lambda" | "none" = "curly", + delimiter: "curly" | "paren" | "lambda" | "none" = "curly" ): void { const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" - ? ["(", ")"] - : delimiter === "none" - ? ["", ""] - : ["{", "})"]; + ? ["(", ")"] + : delimiter === "none" + ? ["", ""] + : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); } - protected anySourceType (optional: boolean): Sourcelike { + protected anySourceType(optional: boolean): Sourcelike { return [wrapOption("Any", optional)]; } // (asarazan): I've broken out the following two functions // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType (arrayType: ArrayType, withIssues = false): Sourcelike { + protected arrayType(arrayType: ArrayType, withIssues = false): Sourcelike { return ["Seq[", this.scalaType(arrayType.items, withIssues), "]"]; } - protected mapType (mapType: MapType, withIssues = false): Sourcelike { + protected mapType(mapType: MapType, withIssues = false): Sourcelike { return ["Map[String, ", this.scalaType(mapType.values, withIssues), "]"]; } - protected scalaType (t: Type, withIssues = false, noOptional = false): Sourcelike { + protected scalaType(t: Type, withIssues = false, noOptional = false): Sourcelike { return matchType( t, _anyType => { @@ -302,15 +302,15 @@ export class Scala3Renderer extends ConvenienceRenderer { } return this.nameForNamedType(unionType); - }, + } ); } - protected emitUsageHeader (): void { + protected emitUsageHeader(): void { // To be overridden } - protected emitHeader (): void { + protected emitHeader(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -322,22 +322,22 @@ export class Scala3Renderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.scalaType(t.items); this.emitLine(["type ", name, " = List[", elementType, "]"]); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.scalaType(t.values); this.emitLine(["type ", name, " = Map[String, ", elementType, "]"]); } - protected emitEmptyClassDefinition (c: ClassType, className: Name): void { + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("case class ", className, "()"); } - protected emitClassDefinition (c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name): void { if (c.getProperties().size === 0) { this.emitEmptyClassDefinition(c, className); return; @@ -383,7 +383,7 @@ export class Scala3Renderer extends ConvenienceRenderer { " : ", scalaType(p), p.isOptional ? " = None" : nullableOrOptional ? " = None" : "", - last ? "" : ",", + last ? "" : "," ); if (meta.length > 0 && !last) { @@ -397,11 +397,11 @@ export class Scala3Renderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(); } - protected emitClassDefinitionMethods () { + protected emitClassDefinitionMethods() { this.emitLine(")"); } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock( @@ -433,12 +433,12 @@ export class Scala3Renderer extends ConvenienceRenderer { } }); }, - "none", + "none" ); } - protected emitUnionDefinition (u: UnionType, unionName: Name): void { - function sortBy (t: Type): string { + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -462,7 +462,7 @@ export class Scala3Renderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.emitHeader(); // Top-level arrays, maps @@ -478,17 +478,17 @@ export class Scala3Renderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n), + (u, n) => this.emitUnionDefinition(u, n) ); } } export class UpickleRenderer extends Scala3Renderer { - protected emitClassDefinitionMethods () { + protected emitClassDefinitionMethods() { this.emitLine(") derives ReadWriter "); } - protected emitHeader (): void { + protected emitHeader(): void { super.emitHeader(); this.emitLine("import upickle.default.*"); @@ -497,7 +497,7 @@ export class UpickleRenderer extends Scala3Renderer { } export class Smithy4sRenderer extends Scala3Renderer { - protected emitHeader (): void { + protected emitHeader(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -509,22 +509,22 @@ export class Smithy4sRenderer extends Scala3Renderer { this.ensureBlankLine(); } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.scalaType(t.items); this.emitLine(["list ", name, " { member : ", elementType, "}"]); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.scalaType(t.values); this.emitLine(["map ", name, " { map[ key : String , value : ", elementType, "}"]); } - protected emitEmptyClassDefinition (c: ClassType, className: Name): void { + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("structure ", className, "{}"); } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.ensureBlankLine(); @@ -538,7 +538,7 @@ export class Smithy4sRenderer extends Scala3Renderer { !isNaN(parseInt(jsonName.charAt(0))) if (backticks) {this.emitItem("`")} else */ this.emitLine(); - this.emitItem([name, " = \"", jsonName, "\""]); + this.emitItem([name, ' = "', jsonName, '"']); // if (backticks) {this.emitItem("`")} if (--count > 0) this.emitItem([","]); // } else { @@ -553,7 +553,7 @@ export class Smithy4sRenderer extends Scala3Renderer { export class CirceRenderer extends Scala3Renderer { seenUnionTypes: string[] = []; - protected circeEncoderForType (t: Type, _ = false, noOptional = false, paramName: string = ""): Sourcelike { + protected circeEncoderForType(t: Type, _ = false, noOptional = false, paramName: string = ""): Sourcelike { return matchType( t, _anyType => ["Encoder.encodeJson(", paramName, ")"], @@ -577,25 +577,25 @@ export class CirceRenderer extends Scala3Renderer { } return ["Encoder.AsObject[", this.nameForNamedType(unionType), "]"]; - }, + } ); } - protected emitEmptyClassDefinition (c: ClassType, className: Name): void { + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.ensureBlankLine(); this.emitLine("case class ", className, "() derives Encoder.AsObject, Decoder"); } - protected anySourceType (optional: boolean): Sourcelike { + protected anySourceType(optional: boolean): Sourcelike { return [wrapOption("Json", optional)]; } - protected emitClassDefinitionMethods () { + protected emitClassDefinitionMethods() { this.emitLine(") derives Encoder.AsObject, Decoder"); } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.ensureBlankLine(); @@ -608,7 +608,7 @@ export class CirceRenderer extends Scala3Renderer { jsonName.includes(" ") || !isNaN(parseInt(jsonName.charAt(0))) if (backticks) {this.emitItem("`")} else */ - this.emitItem(["\"", jsonName, "\""]); + this.emitItem(['"', jsonName, '"']); // if (backticks) {this.emitItem("`")} if (--count > 0) this.emitItem([" | "]); // } else { @@ -618,7 +618,7 @@ export class CirceRenderer extends Scala3Renderer { this.ensureBlankLine(); } - protected emitHeader (): void { + protected emitHeader(): void { super.emitHeader(); this.emitLine("import scala.util.Try"); @@ -629,17 +629,17 @@ export class CirceRenderer extends Scala3Renderer { this.emitLine("// For serialising string unions"); this.emitLine( - "given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) ", + "given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) " ); this.emitLine( - "given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) ", + "given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) " ); this.ensureBlankLine(); this.emitLine("// If a union has a null in, then we'll need this too... "); this.emitLine("type NullValue = None.type"); } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { super.emitTopLevelArray(t, name); const elementType = this.scalaType(t.items); this.emitLine([ @@ -649,11 +649,11 @@ export class CirceRenderer extends Scala3Renderer { elementType, "]] = Encoder.encodeMap[String, ", elementType, - "]", + "]" ]); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { super.emitTopLevelMap(t, name); const elementType = this.scalaType(t.values); this.ensureBlankLine(); @@ -664,12 +664,12 @@ export class CirceRenderer extends Scala3Renderer { elementType, "]] = Encoder.encodeMap[String, ", elementType, - "]", + "]" ]); } - protected emitUnionDefinition (u: UnionType, unionName: Name): void { - function sortBy (t: Type): string { + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -727,7 +727,7 @@ export class CirceRenderer extends Scala3Renderer { " : ", t[0], " => ", - this.circeEncoderForType(t[1], false, false, paramTemp), + this.circeEncoderForType(t[1], false, false, paramTemp) ]); }); }); @@ -737,25 +737,25 @@ export class CirceRenderer extends Scala3Renderer { } export class Scala3TargetLanguage extends TargetLanguage { - constructor () { + constructor() { super("Scala3", ["scala3"], "scala"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [scala3Options.framework, scala3Options.packageName]; } - get supportsOptionalClassProperties (): boolean { + get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes (): boolean { + get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): ConvenienceRenderer { const options = getOptionValues(scala3Options, untypedOptionValues); diff --git a/packages/quicktype-core/src/language/Smithy4s.ts b/packages/quicktype-core/src/language/Smithy4s.ts index 8e794fbd5..816da3125 100644 --- a/packages/quicktype-core/src/language/Smithy4s.ts +++ b/packages/quicktype-core/src/language/Smithy4s.ts @@ -1,11 +1,11 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated } from "../Source"; import { allLowerWordStyle, @@ -16,7 +16,7 @@ import { isLetterOrUnderscore, isNumeric, legalizeCharacters, - splitIntoWords, + splitIntoWords } from "../support/Strings"; import { assertNever } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; @@ -26,12 +26,12 @@ import { matchCompoundType, matchType, nullableFromUnion, removeNullFromUnion } import { type RenderContext } from "../Renderer"; export enum Framework { - None + None = "None" } export const SmithyOptions = { framework: new EnumOption("framework", "Serialization framework", [["just-types", Framework.None]], undefined), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") }; // Use backticks for param names with symbols @@ -53,13 +53,13 @@ const invalidSymbols = [ "/", ";", "'", - "\"", + '"', "{", "}", ":", "~", "`", - ".", + "." ]; const keywords = [ @@ -109,7 +109,7 @@ const keywords = [ "Array", "List", "Map", - "Enum", + "Enum" ]; /** @@ -125,17 +125,17 @@ const shouldAddBacktick = (paramName: string): boolean => { ); }; -function isPartCharacter (codePoint: number): boolean { +function isPartCharacter(codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter (codePoint: number): boolean { +function isStartCharacter(codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function scalaNameStyle (isUpper: boolean, original: string): string { +function scalaNameStyle(isUpper: boolean, original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -145,7 +145,7 @@ function scalaNameStyle (isUpper: boolean, original: string): string { isUpper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter, + isStartCharacter ); } @@ -153,93 +153,93 @@ const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s) const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); export class Smithy4sRenderer extends ConvenienceRenderer { - constructor ( + constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _scalaOptions: OptionValues, + protected readonly _scalaOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords; } - protected forbiddenForObjectProperties (_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected topLevelNameStyle (rawName: string): string { + protected topLevelNameStyle(rawName: string): string { return scalaNameStyle(true, rawName); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return upperNamingFunction; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return lowerNamingFunction; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - protected emitBlock ( + protected emitBlock( line: Sourcelike, f: () => void, - delimiter: "curly" | "paren" | "lambda" | "none" = "curly", + delimiter: "curly" | "paren" | "lambda" | "none" = "curly" ): void { const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" - ? ["(", ")"] - : delimiter === "none" - ? ["", ""] - : ["{", "})"]; + ? ["(", ")"] + : delimiter === "none" + ? ["", ""] + : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); } - protected anySourceType (_: boolean): Sourcelike { + protected anySourceType(_: boolean): Sourcelike { return ["Document"]; } // (asarazan): I've broken out the following two functions // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType (arrayType: ArrayType, _ = false): Sourcelike { + protected arrayType(arrayType: ArrayType, _ = false): Sourcelike { // this.emitTopLevelArray(arrayType, new Name(arrayType.getCombinedName().toString() + "List")) return arrayType.getCombinedName().toString() + "List"; } - protected emitArrayType (_: ArrayType, smithyType: Sourcelike): void { + protected emitArrayType(_: ArrayType, smithyType: Sourcelike): void { this.emitLine(["list ", smithyType, " { member : ", "}"]); } - protected mapType (mapType: MapType, _ = false): Sourcelike { + protected mapType(mapType: MapType, _ = false): Sourcelike { return mapType.getCombinedName().toString() + "Map"; // return [this.scalaType(mapType.values, withIssues), "Map"]; } - protected scalaType (t: Type, withIssues = false, noOptional = false): Sourcelike { + protected scalaType(t: Type, withIssues = false, noOptional = false): Sourcelike { return matchType( t, _anyType => { @@ -264,15 +264,15 @@ export class Smithy4sRenderer extends ConvenienceRenderer { } return this.nameForNamedType(unionType); - }, + } ); } - protected emitUsageHeader (): void { + protected emitUsageHeader(): void { // To be overridden } - protected emitHeader (): void { + protected emitHeader(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { @@ -280,7 +280,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { } this.ensureBlankLine(); - this.emitLine("$version: \"2\""); + this.emitLine('$version: "2"'); this.emitLine("namespace ", this._scalaOptions.packageName); this.ensureBlankLine(); @@ -288,22 +288,22 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - protected emitTopLevelArray (t: ArrayType, name: Name): void { + protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.scalaType(t.items); this.emitLine(["list ", name, " { member : ", elementType, "}"]); } - protected emitTopLevelMap (t: MapType, name: Name): void { + protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.scalaType(t.values); this.emitLine(["map ", name, " { map[ key : String , value : ", elementType, "}"]); } - protected emitEmptyClassDefinition (c: ClassType, className: Name): void { + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("structure ", className, "{}"); } - protected emitClassDefinition (c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name): void { if (c.getProperties().size === 0) { this.emitEmptyClassDefinition(c, className); return; @@ -357,7 +357,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { " : ", scalaType(p), - last ? "" : ",", + last ? "" : "," ); if (meta.length > 0 && !last) { @@ -370,10 +370,10 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(emitLater); } - protected emitClassDefinitionMethods (arrayTypes: ClassProperty[]) { + protected emitClassDefinitionMethods(arrayTypes: ClassProperty[]) { this.emitLine("}"); arrayTypes.forEach(p => { - function ignore (_: T): void { + function ignore(_: T): void { return; } @@ -385,7 +385,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(at, true), "{ member: ", this.scalaType(at.items, true), - "}", + "}" ]); }, ignore, @@ -395,16 +395,16 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(mt, true), "{ key: String , value: ", this.scalaType(mt.values, true), - "}", + "}" ]); }, ignore, - ignore, + ignore ); }); } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.ensureBlankLine(); @@ -420,7 +420,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { if (backticks) {this.emitItem("`")} else */ this.emitLine(); - this.emitItem([name, " = \"", jsonName, "\""]); + this.emitItem([name, ' = "', jsonName, '"']); // if (backticks) {this.emitItem("`")} if (--count > 0) this.emitItem([","]); @@ -433,8 +433,8 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.emitItem(["}"]); } - protected emitUnionDefinition (u: UnionType, unionName: Name): void { - function sortBy (t: Type): string { + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -468,7 +468,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.ensureBlankLine(); emitLater.forEach(p => { - function ignore (_: T): void { + function ignore(_: T): void { return; } @@ -480,7 +480,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(at, true), "{ member: ", this.scalaType(at.items, true), - "}", + "}" ]); }, ignore, @@ -490,16 +490,16 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.scalaType(mt, true), "{ key: String , value: ", this.scalaType(mt.values, true), - "}", + "}" ]); }, ignore, - ignore, + ignore ); }); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.emitHeader(); // Top-level arrays, maps @@ -515,31 +515,31 @@ export class Smithy4sRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n), + (u, n) => this.emitUnionDefinition(u, n) ); } } export class SmithyTargetLanguage extends TargetLanguage { - constructor () { + constructor() { super("Smithy", ["Smithy"], "smithy"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [SmithyOptions.framework, SmithyOptions.packageName]; } - get supportsOptionalClassProperties (): boolean { + get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes (): boolean { + get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): ConvenienceRenderer { const options = getOptionValues(SmithyOptions, untypedOptionValues); From 885b35a903fdf80404e5de123b9c5b4e042aecf4 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Thu, 11 Apr 2024 09:09:00 -0700 Subject: [PATCH 17/80] add all missing accessibility modifiers fixup! add all missing accessibility modifiers fixup! add all missing accessibility modifiers --- packages/quicktype-core/src/Annotation.ts | 6 +- .../quicktype-core/src/ConvenienceRenderer.ts | 259 +++++------ packages/quicktype-core/src/CycleBreaker.ts | 9 +- packages/quicktype-core/src/DateTime.ts | 7 +- packages/quicktype-core/src/DeclarationIR.ts | 27 +- packages/quicktype-core/src/GatherNames.ts | 28 +- packages/quicktype-core/src/Graph.ts | 36 +- packages/quicktype-core/src/GraphRewriting.ts | 191 ++++---- .../quicktype-core/src/MakeTransformations.ts | 108 ++--- packages/quicktype-core/src/MarkovChain.ts | 26 +- packages/quicktype-core/src/Messages.ts | 143 +++--- packages/quicktype-core/src/Naming.ts | 122 ++--- packages/quicktype-core/src/Renderer.ts | 95 ++-- .../quicktype-core/src/RendererOptions.ts | 44 +- packages/quicktype-core/src/Run.ts | 161 ++++--- packages/quicktype-core/src/Source.ts | 50 +- packages/quicktype-core/src/TargetLanguage.ts | 40 +- packages/quicktype-core/src/Transformers.ts | 426 +++++++++-------- packages/quicktype-core/src/Type.ts | 302 ++++++------ packages/quicktype-core/src/TypeBuilder.ts | 187 ++++---- packages/quicktype-core/src/TypeGraph.ts | 161 +++---- packages/quicktype-core/src/TypeUtils.ts | 102 ++-- packages/quicktype-core/src/UnifyClasses.ts | 54 +-- packages/quicktype-core/src/UnionBuilder.ts | 97 ++-- .../src/attributes/AccessorNames.ts | 48 +- .../src/attributes/Constraints.ts | 54 +-- .../src/attributes/Description.ts | 32 +- .../src/attributes/EnumValues.ts | 12 +- .../src/attributes/StringTypes.ts | 58 +-- .../src/attributes/TypeAttributes.ts | 54 +-- .../src/attributes/TypeNames.ts | 94 ++-- .../src/attributes/URIAttributes.ts | 20 +- .../src/input/CompressedJSON.ts | 26 +- .../src/input/FetchingJSONSchemaStore.ts | 6 +- .../quicktype-core/src/input/Inference.ts | 66 ++- packages/quicktype-core/src/input/Inputs.ts | 61 +-- .../src/input/JSONSchemaInput.ts | 86 ++-- .../src/input/JSONSchemaStore.ts | 8 +- packages/quicktype-core/src/language/CJSON.ts | 8 +- .../quicktype-core/src/language/CPlusPlus.ts | 36 +- .../quicktype-core/src/language/CSharp.ts | 22 +- .../quicktype-core/src/language/Crystal.ts | 80 ++-- packages/quicktype-core/src/language/Dart.ts | 196 ++++---- packages/quicktype-core/src/language/Elm.ts | 136 +++--- .../quicktype-core/src/language/Golang.ts | 120 ++--- .../quicktype-core/src/language/Haskell.ts | 122 ++--- .../quicktype-core/src/language/JSONSchema.ts | 60 +-- packages/quicktype-core/src/language/Java.ts | 434 +++++++++--------- .../quicktype-core/src/language/JavaScript.ts | 140 +++--- .../src/language/JavaScriptPropTypes.ts | 91 ++-- .../src/language/JavaScriptUnicodeMaps.ts | 25 +- .../quicktype-core/src/language/Kotlin.ts | 14 +- .../src/language/Objective-C.ts | 225 ++++----- packages/quicktype-core/src/language/Php.ts | 222 ++++----- packages/quicktype-core/src/language/Pike.ts | 80 ++-- .../quicktype-core/src/language/Python.ts | 390 ++++++++-------- packages/quicktype-core/src/language/Rust.ts | 4 +- .../quicktype-core/src/language/Scala3.ts | 18 +- .../quicktype-core/src/language/Smithy4s.ts | 16 +- packages/quicktype-core/src/language/Swift.ts | 220 +++++---- .../src/language/TypeScriptEffectSchema.ts | 68 +-- .../src/language/TypeScriptFlow.ts | 128 +++--- .../src/language/TypeScriptZod.ts | 85 ++-- .../quicktype-core/src/language/ruby/index.ts | 126 ++--- .../src/rewrites/CombineClasses.ts | 28 +- .../src/rewrites/ExpandStrings.ts | 24 +- .../src/rewrites/FlattenStrings.ts | 16 +- .../src/rewrites/FlattenUnions.ts | 10 +- .../quicktype-core/src/rewrites/InferMaps.ts | 22 +- .../src/rewrites/ReplaceObjectType.ts | 16 +- .../src/rewrites/ResolveIntersections.ts | 93 ++-- packages/quicktype-core/src/support/Chance.ts | 61 +-- .../quicktype-core/src/support/Comments.ts | 6 +- .../quicktype-core/src/support/Converters.ts | 6 +- .../quicktype-core/src/support/Strings.ts | 188 ++++---- .../quicktype-core/src/support/Support.ts | 48 +- packages/quicktype-graphql-input/src/index.ts | 110 ++--- src/CompressedJSONFromStream.ts | 14 +- 78 files changed, 3540 insertions(+), 3474 deletions(-) diff --git a/packages/quicktype-core/src/Annotation.ts b/packages/quicktype-core/src/Annotation.ts index e6483462c..38cb82622 100644 --- a/packages/quicktype-core/src/Annotation.ts +++ b/packages/quicktype-core/src/Annotation.ts @@ -1,14 +1,14 @@ export class AnnotationData {} export class IssueAnnotationData extends AnnotationData { - constructor (readonly message: string) { + public constructor(public readonly message: string) { super(); } } export const anyTypeIssueAnnotation = new IssueAnnotationData( - "quicktype cannot infer this type because there is no data about it in the input.", + "quicktype cannot infer this type because there is no data about it in the input." ); export const nullTypeIssueAnnotation = new IssueAnnotationData( - "The only value for this in the input is null, which means you probably need a more complete input sample.", + "The only value for this in the input is null, which means you probably need a more complete input sample." ); diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index 175db7e3e..7fd2041db 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -6,19 +6,19 @@ import { mapFilter, mapSortBy, mapFilterMap, - mapSome, + mapSome } from "collection-utils"; -import { type Type, type TypeKind, type ClassProperty} from "./Type"; +import { type Type, type TypeKind, type ClassProperty } from "./Type"; import { ClassType, EnumType, UnionType, MapType, ObjectType } from "./Type"; import { separateNamedTypes, nullableFromUnion, matchTypeExhaustive, isNamedType } from "./TypeUtils"; -import { type Name, type Namer} from "./Naming"; +import { type Name, type Namer } from "./Naming"; import { Namespace, FixedName, SimpleName, DependencyName, keywordNamespace } from "./Naming"; import { type BlankLineConfig, type RenderContext, type ForEachPosition } from "./Renderer"; import { Renderer } from "./Renderer"; import { defined, panic, nonNull, assert } from "./support/Support"; import { trimEnd } from "./support/Strings"; -import { type Sourcelike} from "./Source"; +import { type Sourcelike } from "./Source"; import { sourcelikeToSource, serializeRenderResult } from "./Source"; import { type DeclarationIR, type Declaration } from "./DeclarationIR"; @@ -47,7 +47,7 @@ const assignedEnumCaseNameOrder = 10; const unionMemberNameOrder = 40; -function splitDescription (descriptions: Iterable | undefined): string[] | undefined { +function splitDescription(descriptions: Iterable | undefined): string[] | undefined { if (descriptions === undefined) return undefined; const description = Array.from(descriptions).join("\n\n").trim(); if (description === "") return undefined; @@ -57,7 +57,8 @@ function splitDescription (descriptions: Iterable | undefined): string[] } export interface ForbiddenWordsInfo { - includeGlobalForbidden: boolean; names: Array; + includeGlobalForbidden: boolean; + names: Array; } const assignedNameAttributeKind = new TypeAttributeKind("assignedName"); @@ -110,11 +111,11 @@ export abstract class ConvenienceRenderer extends Renderer { private _alphabetizeProperties = false; - constructor (targetLanguage: TargetLanguage, renderContext: RenderContext) { + public constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) { super(targetLanguage, renderContext); } - get topLevels (): ReadonlyMap { + public get topLevels(): ReadonlyMap { return this.typeGraph.topLevels; } @@ -125,7 +126,7 @@ export abstract class ConvenienceRenderer extends Renderer { * that can conflict with that, such as reserved keywords or common type * names. */ - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return []; } @@ -139,37 +140,37 @@ export abstract class ConvenienceRenderer extends Renderer { * Note: That doesn't mean that the names in the global namespace will be * forbidden, too! */ - protected forbiddenForObjectProperties (_o: ObjectType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_o: ObjectType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: false }; } - protected makeTopLevelDependencyNames (_t: Type, _topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames(_t: Type, _topLevelName: Name): DependencyName[] { return []; } - protected makeNamedTypeDependencyNames (_t: Type, _name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames(_t: Type, _name: Name): DependencyName[] { return []; } - protected abstract makeNamedTypeNamer (): Namer; - protected abstract namerForObjectProperty (o: ObjectType, p: ClassProperty): Namer | null; - protected abstract makeUnionMemberNamer (): Namer | null; - protected abstract makeEnumCaseNamer (): Namer | null; - protected abstract emitSourceStructure (givenOutputFilename: string): void; + protected abstract makeNamedTypeNamer(): Namer; + protected abstract namerForObjectProperty(o: ObjectType, p: ClassProperty): Namer | null; + protected abstract makeUnionMemberNamer(): Namer | null; + protected abstract makeEnumCaseNamer(): Namer | null; + protected abstract emitSourceStructure(givenOutputFilename: string): void; - protected makeNameForTransformation (_xf: Transformation, _typeName: Name | undefined): Name | undefined { + protected makeNameForTransformation(_xf: Transformation, _typeName: Name | undefined): Name | undefined { return undefined; } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { if (isNamedType(type)) { return type; } @@ -177,58 +178,58 @@ export abstract class ConvenienceRenderer extends Renderer { return undefined; } - protected get unionMembersInGlobalNamespace (): boolean { + protected get unionMembersInGlobalNamespace(): boolean { return false; } - protected get enumCasesInGlobalNamespace (): boolean { + protected get enumCasesInGlobalNamespace(): boolean { return false; } - protected get needsTypeDeclarationBeforeUse (): boolean { + protected get needsTypeDeclarationBeforeUse(): boolean { return false; } - protected canBeForwardDeclared (_t: Type): boolean { + protected canBeForwardDeclared(_t: Type): boolean { return panic("If needsTypeDeclarationBeforeUse returns true, canBeForwardDeclared must be implemented"); } - protected unionNeedsName (u: UnionType): boolean { + protected unionNeedsName(u: UnionType): boolean { return nullableFromUnion(u) === null; } - private get globalNamespace (): Namespace { + private get globalNamespace(): Namespace { return defined(this._globalNamespace); } - private get nameStoreView (): TypeAttributeStoreView { + private get nameStoreView(): TypeAttributeStoreView { return defined(this._nameStoreView); } - protected descriptionForType (t: Type): string[] | undefined { + protected descriptionForType(t: Type): string[] | undefined { let description = this.typeGraph.attributeStore.tryGet(descriptionTypeAttributeKind, t); return splitDescription(description); } - protected descriptionForClassProperty (o: ObjectType, name: string): string[] | undefined { + protected descriptionForClassProperty(o: ObjectType, name: string): string[] | undefined { const descriptions = this.typeGraph.attributeStore.tryGet(propertyDescriptionsTypeAttributeKind, o); if (descriptions === undefined) return undefined; return splitDescription(descriptions.get(name)); } - protected setUpNaming (): ReadonlySet { + protected setUpNaming(): ReadonlySet { this._nameStoreView = new TypeAttributeStoreView(this.typeGraph.attributeStore, assignedNameAttributeKind); this._propertyNamesStoreView = new TypeAttributeStoreView( this.typeGraph.attributeStore, - assignedPropertyNamesAttributeKind, + assignedPropertyNamesAttributeKind ); this._memberNamesStoreView = new TypeAttributeStoreView( this.typeGraph.attributeStore, - assignedMemberNamesAttributeKind, + assignedMemberNamesAttributeKind ); this._caseNamesStoreView = new TypeAttributeStoreView( this.typeGraph.attributeStore, - assignedCaseNamesAttributeKind, + assignedCaseNamesAttributeKind ); this._namesForTransformations = new Map(); @@ -266,22 +267,22 @@ export abstract class ConvenienceRenderer extends Renderer { return setUnion( [this._globalForbiddenNamespace, this._globalNamespace], - this._otherForbiddenNamespaces.values(), + this._otherForbiddenNamespaces.values() ); } - private addDependenciesForNamedType (type: Type, named: Name): void { + private addDependenciesForNamedType(type: Type, named: Name): void { const dependencyNames = this.makeNamedTypeDependencyNames(type, named); for (const dn of dependencyNames) { this.globalNamespace.add(dn); } } - protected makeNameForTopLevel (_t: Type, givenName: string, _maybeNamedType: Type | undefined): Name { + protected makeNameForTopLevel(_t: Type, givenName: string, _maybeNamedType: Type | undefined): Name { return new SimpleName([givenName], defined(this._namedTypeNamer), topLevelNameOrder); } - private addNameForTopLevel (type: Type, givenName: string): Name { + private addNameForTopLevel(type: Type, givenName: string): Name { const maybeNamedType = this.namedTypeToNameForTopLevel(type); const name = this.makeNameForTopLevel(type, givenName, maybeNamedType); this.globalNamespace.add(name); @@ -298,17 +299,17 @@ export abstract class ConvenienceRenderer extends Renderer { return name; } - private makeNameForType (t: Type, namer: Namer, givenOrder: number, inferredOrder: number): Name { + private makeNameForType(t: Type, namer: Namer, givenOrder: number, inferredOrder: number): Name { const names = t.getNames(); const order = names.areInferred ? inferredOrder : givenOrder; return new SimpleName(names.proposedNames, namer, order); } - protected makeNameForNamedType (t: Type): Name { + protected makeNameForNamedType(t: Type): Name { return this.makeNameForType(t, defined(this._namedTypeNamer), givenNameOrder, inferredNameOrder); } - private addNameForNamedType (type: Type): Name { + private addNameForNamedType(type: Type): Name { const existing = this.nameStoreView.tryGet(type); if (existing !== undefined) return existing; @@ -320,11 +321,11 @@ export abstract class ConvenienceRenderer extends Renderer { return name; } - protected get typesWithNamedTransformations (): ReadonlyMap { + protected get typesWithNamedTransformations(): ReadonlyMap { return defined(this._namesForTransformations); } - protected nameForTransformation (t: Type): Name | undefined { + protected nameForTransformation(t: Type): Name | undefined { const xf = transformationForType(t); if (xf === undefined) return undefined; @@ -336,13 +337,13 @@ export abstract class ConvenienceRenderer extends Renderer { return name; } - private addNameForTransformation (t: Type): void { + private addNameForTransformation(t: Type): void { const xf = transformationForType(t); if (xf === undefined) return; assert( defined(this._namesForTransformations).get(t) === undefined, - "Tried to give two names to the same transformation", + "Tried to give two names to the same transformation" ); const name = this.makeNameForTransformation(xf, this.nameStoreView.tryGet(xf.targetType)); @@ -352,10 +353,10 @@ export abstract class ConvenienceRenderer extends Renderer { defined(this._namesForTransformations).set(t, name); } - private processForbiddenWordsInfo ( + private processForbiddenWordsInfo( info: ForbiddenWordsInfo, - namespaceName: string, - ): { forbiddenNames: ReadonlySet, forbiddenNamespaces: ReadonlySet, } { + namespaceName: string + ): { forbiddenNames: ReadonlySet; forbiddenNamespaces: ReadonlySet } { const forbiddenNames: Name[] = []; const forbiddenStrings: string[] = []; for (const nameOrString of info.names) { @@ -384,12 +385,12 @@ export abstract class ConvenienceRenderer extends Renderer { return { forbiddenNames: new Set(forbiddenNames), forbiddenNamespaces }; } - protected makeNameForProperty ( + protected makeNameForProperty( o: ObjectType, _className: Name, p: ClassProperty, jsonName: string, - assignedName: string | undefined, + assignedName: string | undefined ): Name | undefined { const namer = this.namerForObjectProperty(o, p); if (namer === null) return undefined; @@ -408,20 +409,20 @@ export abstract class ConvenienceRenderer extends Renderer { return new SimpleName(names, namer, order); } - protected makePropertyDependencyNames ( + protected makePropertyDependencyNames( _o: ObjectType, _className: Name, _p: ClassProperty, _jsonName: string, - _name: Name, + _name: Name ): Name[] { return []; } - private addPropertyNames (o: ObjectType, className: Name): void { + private addPropertyNames(o: ObjectType, className: Name): void { const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( this.forbiddenForObjectProperties(o, className), - "forbidden-for-properties", + "forbidden-for-properties" ); let ns: Namespace | undefined; @@ -451,7 +452,7 @@ export abstract class ConvenienceRenderer extends Renderer { defined(this._propertyNamesStoreView).set(o, names); } - protected makeNameForUnionMember (u: UnionType, unionName: Name, t: Type): Name { + protected makeNameForUnionMember(u: UnionType, unionName: Name, t: Type): Name { const [assignedName, isFixed] = unionMemberName(u, t, this.targetLanguage.name); if (isFixed) { return new FixedName(defined(assignedName)); @@ -463,13 +464,13 @@ export abstract class ConvenienceRenderer extends Renderer { }); } - private addUnionMemberNames (u: UnionType, unionName: Name): void { + private addUnionMemberNames(u: UnionType, unionName: Name): void { const memberNamer = this._unionMemberNamer; if (memberNamer === null) return; const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( this.forbiddenForUnionMembers(u, unionName), - "forbidden-for-union-members", + "forbidden-for-union-members" ); let ns: Namespace; @@ -488,11 +489,11 @@ export abstract class ConvenienceRenderer extends Renderer { defined(this._memberNamesStoreView).set(u, names); } - protected makeNameForEnumCase ( + protected makeNameForEnumCase( e: EnumType, _enumName: Name, caseName: string, - assignedName: string | undefined, + assignedName: string | undefined ): Name { // FIXME: See the FIXME in `makeNameForProperty`. We do have global // enum cases, though (in Go), so this is actually useful already. @@ -503,12 +504,12 @@ export abstract class ConvenienceRenderer extends Renderer { } // FIXME: this is very similar to addPropertyNameds and addUnionMemberNames - private addEnumCaseNames (e: EnumType, enumName: Name): void { + private addEnumCaseNames(e: EnumType, enumName: Name): void { if (this._enumCaseNamer === null) return; const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( this.forbiddenForEnumCases(e, enumName), - "forbidden-for-enum-cases", + "forbidden-for-enum-cases" ); let ns: Namespace; @@ -535,7 +536,7 @@ export abstract class ConvenienceRenderer extends Renderer { defined(this._caseNamesStoreView).set(e, names); } - private childrenOfType (t: Type): ReadonlySet { + private childrenOfType(t: Type): ReadonlySet { const names = this.names; if (t instanceof ClassType) { const propertyNameds = defined(this._propertyNamesStoreView).get(t); @@ -550,49 +551,49 @@ export abstract class ConvenienceRenderer extends Renderer { return t.getChildren(); } - protected get namedUnions (): ReadonlySet { + protected get namedUnions(): ReadonlySet { return defined(this._namedUnions); } - protected get haveNamedUnions (): boolean { + protected get haveNamedUnions(): boolean { return this.namedUnions.size > 0; } - protected get haveNamedTypes (): boolean { + protected get haveNamedTypes(): boolean { return defined(this._namedTypes).length > 0; } - protected get haveUnions (): boolean { + protected get haveUnions(): boolean { return defined(this._haveUnions); } - protected get haveMaps (): boolean { + protected get haveMaps(): boolean { return defined(this._haveMaps); } - protected get haveOptionalProperties (): boolean { + protected get haveOptionalProperties(): boolean { return defined(this._haveOptionalProperties); } // FIXME: Inconsistently named, though technically correct. Right now all enums are named, // but this should really be called `namedEnums`. - protected get enums (): ReadonlySet { + protected get enums(): ReadonlySet { return defined(this._namedEnums); } - protected get haveEnums (): boolean { + protected get haveEnums(): boolean { return this.enums.size > 0; } - protected proposedUnionMemberNameForTypeKind (_kind: TypeKind): string | null { + protected proposedUnionMemberNameForTypeKind(_kind: TypeKind): string | null { return null; } - protected proposeUnionMemberName ( + protected proposeUnionMemberName( _u: UnionType, _unionName: Name, fieldType: Type, - lookup: (n: Name) => string, + lookup: (n: Name) => string ): string { const simpleName = this.proposedUnionMemberNameForTypeKind(fieldType.kind); if (simpleName !== null) { @@ -617,50 +618,50 @@ export abstract class ConvenienceRenderer extends Renderer { objectType => { assert( this.targetLanguage.supportsFullObjectType, - "Object type should have been replaced in `replaceObjectType`", + "Object type should have been replaced in `replaceObjectType`" ); return lookup(this.nameForNamedType(objectType)); }, _enumType => "enum", _unionType => "union", - transformedType => transformedType.kind.replace("-", "_"), + transformedType => transformedType.kind.replace("-", "_") ); return typeNameForUnionMember(fieldType); } - protected nameForNamedType (t: Type): Name { + protected nameForNamedType(t: Type): Name { return this.nameStoreView.get(t); } - protected isForwardDeclaredType (t: Type): boolean { + protected isForwardDeclaredType(t: Type): boolean { return defined(this._declarationIR).forwardedTypes.has(t); } - protected isImplicitCycleBreaker (_t: Type): boolean { + protected isImplicitCycleBreaker(_t: Type): boolean { return panic("A renderer that invokes isCycleBreakerType must implement isImplicitCycleBreaker"); } - protected canBreakCycles (_t: Type): boolean { + protected canBreakCycles(_t: Type): boolean { return true; } - protected isCycleBreakerType (t: Type): boolean { + protected isCycleBreakerType(t: Type): boolean { if (this._cycleBreakerTypes === undefined) { this._cycleBreakerTypes = cycleBreakerTypesForGraph( this.typeGraph, s => this.isImplicitCycleBreaker(s), - s => this.canBreakCycles(s), + s => this.canBreakCycles(s) ); } return this._cycleBreakerTypes.has(t); } - protected forEachTopLevel ( + protected forEachTopLevel( blankLocations: BlankLineConfig, f: (t: Type, name: Name, position: ForEachPosition) => void, - predicate?: (t: Type) => boolean, + predicate?: (t: Type) => boolean ): boolean { let topLevels: ReadonlyMap; if (predicate !== undefined) { @@ -670,38 +671,38 @@ export abstract class ConvenienceRenderer extends Renderer { } return this.forEachWithBlankLines(topLevels, blankLocations, (t, name, pos) => - f(t, this.nameStoreView.getForTopLevel(name), pos), + f(t, this.nameStoreView.getForTopLevel(name), pos) ); } - protected forEachDeclaration ( + protected forEachDeclaration( blankLocations: BlankLineConfig, - f: (decl: Declaration, position: ForEachPosition) => void, + f: (decl: Declaration, position: ForEachPosition) => void ) { this.forEachWithBlankLines( iterableEnumerate(defined(this._declarationIR).declarations), blankLocations, - (decl, _, pos) => f(decl, pos), + (decl, _, pos) => f(decl, pos) ); } - setAlphabetizeProperties (value: boolean): void { + public setAlphabetizeProperties(value: boolean): void { this._alphabetizeProperties = value; } - protected getAlphabetizeProperties (): boolean { + protected getAlphabetizeProperties(): boolean { return this._alphabetizeProperties; } // Returns the number of properties defined for the specified object type. - protected propertyCount (o: ObjectType): number { + protected propertyCount(o: ObjectType): number { const propertyNames = defined(this._propertyNamesStoreView).get(o); return propertyNames.size; } - protected sortClassProperties ( + protected sortClassProperties( properties: ReadonlyMap, - propertyNames: ReadonlyMap, + propertyNames: ReadonlyMap ): ReadonlyMap { if (this._alphabetizeProperties) { return mapSortBy(properties, (_p: ClassProperty, jsonName: string) => { @@ -713,10 +714,10 @@ export abstract class ConvenienceRenderer extends Renderer { } } - protected forEachClassProperty ( + protected forEachClassProperty( o: ObjectType, blankLocations: BlankLineConfig, - f: (name: Name, jsonName: string, p: ClassProperty, position: ForEachPosition) => void, + f: (name: Name, jsonName: string, p: ClassProperty, position: ForEachPosition) => void ): void { const propertyNames = defined(this._propertyNamesStoreView).get(o); const sortedProperties = this.sortClassProperties(o.getProperties(), propertyNames); @@ -726,21 +727,21 @@ export abstract class ConvenienceRenderer extends Renderer { }); } - protected nameForUnionMember (u: UnionType, t: Type): Name { + protected nameForUnionMember(u: UnionType, t: Type): Name { return defined(defined(this._memberNamesStoreView).get(u).get(t)); } - protected nameForEnumCase (e: EnumType, caseName: string): Name { + protected nameForEnumCase(e: EnumType, caseName: string): Name { const caseNames = defined(this._caseNamesStoreView).get(e); return defined(caseNames.get(caseName)); } - protected forEachUnionMember ( + protected forEachUnionMember( u: UnionType, members: ReadonlySet | null, blankLocations: BlankLineConfig, sortOrder: ((n: Name, t: Type) => string) | null, - f: (name: Name, t: Type, position: ForEachPosition) => void, + f: (name: Name, t: Type, position: ForEachPosition) => void ): void { const iterateMembers = members === null ? u.members : members; if (sortOrder === null) { @@ -752,19 +753,19 @@ export abstract class ConvenienceRenderer extends Renderer { this.forEachWithBlankLines(sortedMemberNames, blankLocations, f); } - protected forEachEnumCase ( + protected forEachEnumCase( e: EnumType, blankLocations: BlankLineConfig, - f: (name: Name, jsonName: string, position: ForEachPosition) => void, + f: (name: Name, jsonName: string, position: ForEachPosition) => void ): void { const caseNames = defined(this._caseNamesStoreView).get(e); const sortedCaseNames = mapSortBy(caseNames, n => defined(this.names.get(n))); this.forEachWithBlankLines(sortedCaseNames, blankLocations, f); } - protected forEachTransformation ( + protected forEachTransformation( blankLocations: BlankLineConfig, - f: (n: Name, t: Type, position: ForEachPosition) => void, + f: (n: Name, t: Type, position: ForEachPosition) => void ): void { this.forEachWithBlankLines(defined(this._namesForTransformations), blankLocations, f); } @@ -772,31 +773,31 @@ export abstract class ConvenienceRenderer extends Renderer { protected forEachSpecificNamedType( blankLocations: BlankLineConfig, types: Iterable<[any, T]>, - f: (t: T, name: Name, position: ForEachPosition) => void, + f: (t: T, name: Name, position: ForEachPosition) => void ): void { this.forEachWithBlankLines(types, blankLocations, (t, _, pos) => f(t, this.nameForNamedType(t), pos)); } - protected forEachObject ( + protected forEachObject( blankLocations: BlankLineConfig, f: - | ((c: ClassType, className: Name, position: ForEachPosition) => void) - | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void), + | ((c: ClassType, className: Name, position: ForEachPosition) => void) + | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void) ): void { // FIXME: This is ugly. this.forEachSpecificNamedType(blankLocations, defined(this._namedObjects).entries(), f as any); } - protected forEachEnum ( + protected forEachEnum( blankLocations: BlankLineConfig, - f: (u: EnumType, enumName: Name, position: ForEachPosition) => void, + f: (u: EnumType, enumName: Name, position: ForEachPosition) => void ): void { this.forEachSpecificNamedType(blankLocations, this.enums.entries(), f); } - protected forEachUnion ( + protected forEachUnion( blankLocations: BlankLineConfig, - f: (u: UnionType, unionName: Name, position: ForEachPosition) => void, + f: (u: UnionType, unionName: Name, position: ForEachPosition) => void ): void { this.forEachSpecificNamedType(blankLocations, this.namedUnions.entries(), f); } @@ -804,7 +805,7 @@ export abstract class ConvenienceRenderer extends Renderer { protected forEachUniqueUnion( blankLocations: BlankLineConfig, uniqueValue: (u: UnionType) => T, - f: (firstUnion: UnionType, value: T, position: ForEachPosition) => void, + f: (firstUnion: UnionType, value: T, position: ForEachPosition) => void ): void { const firstUnionByValue = new Map(); for (const u of this.namedUnions) { @@ -817,13 +818,13 @@ export abstract class ConvenienceRenderer extends Renderer { this.forEachWithBlankLines(firstUnionByValue, blankLocations, f); } - protected forEachNamedType ( + protected forEachNamedType( blankLocations: BlankLineConfig, objectFunc: - | ((c: ClassType, className: Name, position: ForEachPosition) => void) - | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void), + | ((c: ClassType, className: Name, position: ForEachPosition) => void) + | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void), enumFunc: (e: EnumType, enumName: Name, position: ForEachPosition) => void, - unionFunc: (u: UnionType, unionName: Name, position: ForEachPosition) => void, + unionFunc: (u: UnionType, unionName: Name, position: ForEachPosition) => void ): void { this.forEachWithBlankLines(defined(this._namedTypes).entries(), blankLocations, (t, _, pos) => { const name = this.nameForNamedType(t); @@ -844,15 +845,15 @@ export abstract class ConvenienceRenderer extends Renderer { // You should never have to use this to produce parts of your generated // code. If you need to modify a Name, for example to change its casing, // use `modifySource`. - protected sourcelikeToString (src: Sourcelike): string { + protected sourcelikeToString(src: Sourcelike): string { return serializeRenderResult(sourcelikeToSource(src), this.names, "").lines.join("\n"); } - protected get commentLineStart (): string { + protected get commentLineStart(): string { return "// "; } - protected emitComments (comments: Comment[]): void { + protected emitComments(comments: Comment[]): void { comments.forEach(comment => { if (isStringComment(comment)) { this.emitCommentLines([comment]); @@ -868,15 +869,15 @@ export abstract class ConvenienceRenderer extends Renderer { }); } - protected emitCommentLines ( + protected emitCommentLines( lines: Sourcelike[], { lineStart = this.commentLineStart, firstLineStart = lineStart, lineEnd, beforeComment, - afterComment, - }: CommentOptions = {}, + afterComment + }: CommentOptions = {} ): void { if (beforeComment !== undefined) { this.emitLine(beforeComment); @@ -903,19 +904,19 @@ export abstract class ConvenienceRenderer extends Renderer { } } - protected emitDescription (description: Sourcelike[] | undefined): void { + protected emitDescription(description: Sourcelike[] | undefined): void { if (description === undefined) return; // FIXME: word-wrap this.emitDescriptionBlock(description); } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines); } - protected emitPropertyTable ( + protected emitPropertyTable( c: ClassType, - makePropertyRow: (name: Name, jsonName: string, p: ClassProperty) => Sourcelike[], + makePropertyRow: (name: Name, jsonName: string, p: ClassProperty) => Sourcelike[] ): void { let table: Sourcelike[][] = []; const emitTable = () => { @@ -936,7 +937,7 @@ export abstract class ConvenienceRenderer extends Renderer { emitTable(); } - private processGraph (): void { + private processGraph(): void { this._declarationIR = declarationsForGraph( this.typeGraph, this.needsTypeDeclarationBeforeUse ? t => this.canBeForwardDeclared(t) : undefined, @@ -947,7 +948,7 @@ export abstract class ConvenienceRenderer extends Renderer { } return isNamedType(t); - }, + } ); const types = this.typeGraph.allTypesUnordered(); @@ -962,7 +963,7 @@ export abstract class ConvenienceRenderer extends Renderer { this._namedUnions = new Set(unions); } - protected emitSource (givenOutputFilename: string): void { + protected emitSource(givenOutputFilename: string): void { this.processGraph(); this.emitSourceStructure(givenOutputFilename); } @@ -972,7 +973,7 @@ export abstract class ConvenienceRenderer extends Renderer { const processed = new Set(); const queue = Array.from(this.typeGraph.topLevels.values()); - function visit (t: Type) { + function visit(t: Type) { if (visitedTypes.has(t)) return; for (const c of t.getChildren()) { queue.push(c); diff --git a/packages/quicktype-core/src/CycleBreaker.ts b/packages/quicktype-core/src/CycleBreaker.ts index 586ae8f49..9497d9140 100644 --- a/packages/quicktype-core/src/CycleBreaker.ts +++ b/packages/quicktype-core/src/CycleBreaker.ts @@ -1,6 +1,9 @@ import { assert, panic } from "./support/Support"; -export function breakCycles (outEdges: number[][], chooseBreaker: (cycle: number[]) => [number, T]): Array<[number, T]> { +export function breakCycles( + outEdges: number[][], + chooseBreaker: (cycle: number[]) => [number, T] +): Array<[number, T]> { const numNodes = outEdges.length; const inEdges: number[][] = []; const inDegree: number[] = []; @@ -28,7 +31,7 @@ export function breakCycles (outEdges: number[][], chooseBreaker: (cycle: num } } - function removeNode (node: number): void { + function removeNode(node: number): void { for (const n of outEdges[node]) { assert(inDegree[n] > 0); inDegree[n] -= 1; @@ -51,7 +54,7 @@ export function breakCycles (outEdges: number[][], chooseBreaker: (cycle: num for (;;) { const i = workList.pop(); if (i !== undefined) { - if (done[i] || inDegree[i] === 0 && outDegree[i] === 0) { + if (done[i] || (inDegree[i] === 0 && outDegree[i] === 0)) { done[i] = true; continue; } diff --git a/packages/quicktype-core/src/DateTime.ts b/packages/quicktype-core/src/DateTime.ts index 899daa704..9f2bc4ae8 100644 --- a/packages/quicktype-core/src/DateTime.ts +++ b/packages/quicktype-core/src/DateTime.ts @@ -1,3 +1,4 @@ +/* eslint-disable */ // https://github.com/epoberezkin/ajv/blob/4d76c6fb813b136b6ec4fe74990bc97233d75dea/lib/compile/formats.js /* @@ -37,7 +38,7 @@ export interface DateTimeRecognizer { const DATE_TIME_SEPARATOR = /t|\s/i; export class DefaultDateTimeRecognizer implements DateTimeRecognizer { - isDate (str: string) { + isDate(str: string) { // full-date from http://tools.ietf.org/html/rfc3339#section-5.6 const matches = DATE.exec(str); if (matches === null) return false; @@ -47,7 +48,7 @@ export class DefaultDateTimeRecognizer implements DateTimeRecognizer { return month >= 1 && month <= 12 && day >= 1 && day <= DAYS[month]; } - isTime (str: string): boolean { + isTime(str: string): boolean { const matches = TIME.exec(str); if (matches === null) return false; @@ -57,7 +58,7 @@ export class DefaultDateTimeRecognizer implements DateTimeRecognizer { return hour <= 23 && minute <= 59 && second <= 59; } - isDateTime (str: string): boolean { + isDateTime(str: string): boolean { // http://tools.ietf.org/html/rfc3339#section-5.6 const dateTime = str.split(DATE_TIME_SEPARATOR); return dateTime.length === 2 && this.isDate(dateTime[0]) && this.isTime(dateTime[1]); diff --git a/packages/quicktype-core/src/DeclarationIR.ts b/packages/quicktype-core/src/DeclarationIR.ts index 2a42f716f..47d53d2de 100644 --- a/packages/quicktype-core/src/DeclarationIR.ts +++ b/packages/quicktype-core/src/DeclarationIR.ts @@ -14,18 +14,17 @@ export interface Declaration { } export class DeclarationIR { - readonly declarations: readonly Declaration[]; + public readonly declarations: readonly Declaration[]; - constructor (declarations: Iterable, readonly forwardedTypes: Set) { + public constructor( + declarations: Iterable, + public readonly forwardedTypes: Set + ) { this.declarations = Array.from(declarations); } } -function findBreaker ( - t: Type, - path: readonly Type[], - canBreak: ((t: Type) => boolean) | undefined, -): Type | undefined { +function findBreaker(t: Type, path: readonly Type[], canBreak: ((t: Type) => boolean) | undefined): Type | undefined { const index = path.indexOf(t); if (index < 0) return undefined; if (canBreak === undefined) { @@ -41,16 +40,16 @@ function findBreaker ( return maybeBreaker; } -export function cycleBreakerTypesForGraph ( +export function cycleBreakerTypesForGraph( graph: TypeGraph, isImplicitCycleBreaker: (t: Type) => boolean, - canBreakCycles: (t: Type) => boolean, + canBreakCycles: (t: Type) => boolean ): Set { const visitedTypes = new Set(); const cycleBreakerTypes = new Set(); const queue: Type[] = Array.from(graph.topLevels.values()); - function visit (t: Type, path: Type[]): void { + function visit(t: Type, path: Type[]): void { if (visitedTypes.has(t)) return; if (isImplicitCycleBreaker(t)) { @@ -85,11 +84,11 @@ export function cycleBreakerTypesForGraph ( return cycleBreakerTypes; } -export function declarationsForGraph ( +export function declarationsForGraph( typeGraph: TypeGraph, canBeForwardDeclared: ((t: Type) => boolean) | undefined, childrenOfType: (t: Type) => ReadonlySet, - needsDeclaration: (t: Type) => boolean, + needsDeclaration: (t: Type) => boolean ): DeclarationIR { /* function nodeTitle(t: Type): string { @@ -110,9 +109,9 @@ export function declarationsForGraph ( const forwardedTypes = new Set(); const visitedComponents = new Set>(); - function processGraph (graph: Graph, _writeComponents: boolean): void { + function processGraph(graph: Graph, _writeComponents: boolean): void { const componentsGraph = graph.stronglyConnectedComponents(); - function visitComponent (component: ReadonlySet): void { + function visitComponent(component: ReadonlySet): void { if (visitedComponents.has(component)) return; visitedComponents.add(component); diff --git a/packages/quicktype-core/src/GatherNames.ts b/packages/quicktype-core/src/GatherNames.ts index 85bbeb5ca..e5b7d3b86 100644 --- a/packages/quicktype-core/src/GatherNames.ts +++ b/packages/quicktype-core/src/GatherNames.ts @@ -2,7 +2,7 @@ import * as pluralize from "pluralize"; import { setUnion, setMap, setSortBy } from "collection-utils"; import { type TypeGraph } from "./TypeGraph"; -import { type Type} from "./Type"; +import { type Type } from "./Type"; import { ObjectType } from "./Type"; import { matchCompoundType, nullableFromUnion } from "./TypeUtils"; import { TypeNames, namesTypeAttributeKind, TooManyTypeNames, tooManyNamesThreshold } from "./attributes/TypeNames"; @@ -16,21 +16,21 @@ class UniqueQueue { private _front = 0; - get size (): number { + public get size(): number { return this._queue.length - this._front; } - get isEmpty (): boolean { + public get isEmpty(): boolean { return this.size <= 0; } - push (v: T): void { + public push(v: T): void { if (this._present.has(v)) return; this._queue.push(v); this._present.add(v); } - unshift (): T { + public unshift(): T { assert(!this.isEmpty, "Trying to unshift from an empty queue"); const v = this._queue[this._front]; if (v === undefined) { @@ -86,8 +86,8 @@ class UniqueQueue { // step 1, and its alternatives to a union of its direct and ancestor // alternatives, gathered in steps 2 and 3. -export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: boolean): void { - function setNames (t: Type, tn: TypeNames): void { +export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: boolean): void { + function setNames(t: Type, tn: TypeNames): void { graph.attributeStore.set(namesTypeAttributeKind, t, tn); } @@ -103,7 +103,7 @@ export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: // null means there are too many const namesForType = new Map | null>(); - function addNames (t: Type, names: ReadonlySet | null) { + function addNames(t: Type, names: ReadonlySet | null) { // Always use the type's given names if it has some if (t.hasNames) { const originalNames = t.getNames(); @@ -178,7 +178,7 @@ export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: for (const memberType of members) { addNames(memberType, names); } - }, + } ); } } @@ -198,9 +198,9 @@ export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: const ancestorAlternativesForType = new Map | null>(); const pairsProcessed = new Map>(); - function addAlternatives ( + function addAlternatives( existing: ReadonlySet | undefined, - alternatives: string[], + alternatives: string[] ): ReadonlySet | undefined | null { if (alternatives.length === 0) { return existing; @@ -218,7 +218,7 @@ export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: return null; } - function processType (ancestor: Type | undefined, t: Type, alternativeSuffix: string | undefined) { + function processType(ancestor: Type | undefined, t: Type, alternativeSuffix: string | undefined) { const names = defined(namesForType.get(t)); let processedEntry = pairsProcessed.get(ancestor); @@ -302,7 +302,7 @@ export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: for (const memberType of members) { processType(ancestorForMembers, memberType, undefined); } - }, + } ); } } @@ -327,7 +327,7 @@ export function gatherNames (graph: TypeGraph, destructive: boolean, debugPrint: alternatives = setUnion( alternatives, - setMap(names, name => `${name}_${t.kind}`), + setMap(names, name => `${name}_${t.kind}`) ); directAlternativesForType.set(t, alternatives); } diff --git a/packages/quicktype-core/src/Graph.ts b/packages/quicktype-core/src/Graph.ts index 5bcf6ba87..c54e3ed05 100644 --- a/packages/quicktype-core/src/Graph.ts +++ b/packages/quicktype-core/src/Graph.ts @@ -2,7 +2,7 @@ import { setMap } from "collection-utils"; import { defined, repeated, assert, repeatedCall } from "./support/Support"; -function countComponentGraphNodes (components: number[][]): number { +function countComponentGraphNodes(components: number[][]): number { if (components.length === 0) return 0; let largest = -1; @@ -22,7 +22,7 @@ function countComponentGraphNodes (components: number[][]): number { } // https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm -function stronglyConnectedComponents (successors: number[][]): number[][] { +function stronglyConnectedComponents(successors: number[][]): number[][] { let index = 0; const stack: number[] = []; const numNodes = successors.length; @@ -31,7 +31,7 @@ function stronglyConnectedComponents (successors: number[][]): number[][] { const onStack: boolean[] = repeated(numNodes, false); const sccs: number[][] = []; - function strongconnect (v: number): void { + function strongconnect(v: number): void { // Set the depth index for v to the smallest unused index indexes[v] = index; lowLinks[v] = index; @@ -80,7 +80,7 @@ function stronglyConnectedComponents (successors: number[][]): number[][] { return sccs; } -function buildComponentOfNodeMap (successors: number[][], components: number[][]): number[] { +function buildComponentOfNodeMap(successors: number[][], components: number[][]): number[] { const numComponents = components.length; const numNodes = successors.length; @@ -97,7 +97,7 @@ function buildComponentOfNodeMap (successors: number[][], components: number[][] return componentOfNode; } -function buildMetaSuccessors (successors: number[][], components: number[][]): number[][] { +function buildMetaSuccessors(successors: number[][], components: number[][]): number[][] { const numComponents = components.length; const componentOfNode = buildComponentOfNodeMap(successors, components); const componentAdded: boolean[] = repeated(numComponents, false); @@ -127,7 +127,7 @@ function buildMetaSuccessors (successors: number[][], components: number[][]): n return metaSuccessors; } -function invertEdges (successors: number[][]): number[][] { +function invertEdges(successors: number[][]): number[][] { const numNodes = successors.length; const predecessors: number[][] = repeatedCall(numNodes, () => []); @@ -140,7 +140,7 @@ function invertEdges (successors: number[][]): number[][] { return predecessors; } -function calculateInDegrees (successors: number[][]): number[] { +function calculateInDegrees(successors: number[][]): number[] { const numNodes = successors.length; const inDegrees: number[] = repeated(numNodes, 0); @@ -153,7 +153,7 @@ function calculateInDegrees (successors: number[][]): number[] { return inDegrees; } -function findRoots (successors: number[][]): number[] { +function findRoots(successors: number[][]): number[] { const numNodes = successors.length; const inDegrees = calculateInDegrees(successors); const roots: number[] = []; @@ -174,7 +174,11 @@ export class Graph { private readonly _successors: number[][]; - constructor (nodes: Iterable, invertDirection: boolean, edges: number[][] | ((node: T) => ReadonlySet)) { + public constructor( + nodes: Iterable, + invertDirection: boolean, + edges: number[][] | ((node: T) => ReadonlySet) + ) { this._nodes = Array.from(nodes); this._indexByNode = new Map(this._nodes.map((n, i): [T, number] => [n, i])); let edgesArray: number[][]; @@ -191,21 +195,21 @@ export class Graph { this._successors = edgesArray; } - get size (): number { + public get size(): number { return this._nodes.length; } - get nodes (): readonly T[] { + public get nodes(): readonly T[] { return this._nodes; } - findRoots (): ReadonlySet { + public findRoots(): ReadonlySet { const roots = findRoots(this._successors); return new Set(roots.map(n => this._nodes[n])); } // The subgraph starting at `root` must be acyclic. - dfsTraversal (root: T, preOrder: boolean, process: (node: T) => void): void { + public dfsTraversal(root: T, preOrder: boolean, process: (node: T) => void): void { const visited = repeated(this.size, false); const visit = (v: number): void => { @@ -228,17 +232,17 @@ export class Graph { visit(defined(this._indexByNode.get(root))); } - stronglyConnectedComponents (): Graph> { + public stronglyConnectedComponents(): Graph> { const components = stronglyConnectedComponents(this._successors); const componentSuccessors = buildMetaSuccessors(this._successors, components); return new Graph( components.map(ns => setMap(ns, n => this._nodes[n])), false, - componentSuccessors, + componentSuccessors ); } - makeDot (includeNode: (n: T) => boolean, nodeLabel: (n: T) => string): string { + public makeDot(includeNode: (n: T) => boolean, nodeLabel: (n: T) => string): string { const lines: string[] = []; lines.push("digraph G {"); lines.push(" ordering = out;"); diff --git a/packages/quicktype-core/src/GraphRewriting.ts b/packages/quicktype-core/src/GraphRewriting.ts index e4c099fee..e60360890 100644 --- a/packages/quicktype-core/src/GraphRewriting.ts +++ b/packages/quicktype-core/src/GraphRewriting.ts @@ -2,17 +2,9 @@ import { mapMap, EqualityMap } from "collection-utils"; import { type PrimitiveTypeKind, type Type, type ClassProperty, type MaybeTypeIdentity } from "./Type"; import { combineTypeAttributesOfTypes } from "./TypeUtils"; -import { - type TypeGraph, - type TypeRef} from "./TypeGraph"; -import { - derefTypeRef, - typeAndAttributesForTypeRef, - assertTypeRefGraph, - typeRefIndex, - isTypeRef, -} from "./TypeGraph"; -import { type TypeAttributes} from "./attributes/TypeAttributes"; +import { type TypeGraph, type TypeRef } from "./TypeGraph"; +import { derefTypeRef, typeAndAttributesForTypeRef, assertTypeRefGraph, typeRefIndex, isTypeRef } from "./TypeGraph"; +import { type TypeAttributes } from "./attributes/TypeAttributes"; import { emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; import { assert, panic, indentationString } from "./support/Support"; import { type StringTypeMapping } from "./TypeBuilder"; @@ -28,26 +20,26 @@ export class TypeReconstituter { private _typeRef: TypeRef | undefined = undefined; - constructor ( + public constructor( private readonly _typeBuilder: TBuilder, private readonly _makeClassUnique: boolean, private readonly _typeAttributes: TypeAttributes, private readonly _forwardingRef: TypeRef | undefined, - private readonly _register: (tref: TypeRef) => void, + private readonly _register: (tref: TypeRef) => void ) {} - private builderForNewType (): TBuilder { + private builderForNewType(): TBuilder { assert(!this._wasUsed, "TypeReconstituter used more than once"); this._wasUsed = true; return this._typeBuilder; } - private builderForSetting (): TBuilder { + private builderForSetting(): TBuilder { assert(this._wasUsed && this._typeRef !== undefined, "Can't set type members before constructing a type"); return this._typeBuilder; } - getResult (): TypeRef { + public getResult(): TypeRef { if (this._typeRef === undefined) { return panic("Type was not reconstituted"); } @@ -56,20 +48,20 @@ export class TypeReconstituter { } // FIXME: Do registration automatically. - private register (tref: TypeRef): void { + private register(tref: TypeRef): void { assert(this._typeRef === undefined, "Cannot register a type twice"); this._typeRef = tref; this._register(tref); } - private registerAndAddAttributes (tref: TypeRef): void { + private registerAndAddAttributes(tref: TypeRef): void { this._typeBuilder.addAttributes(tref, this._typeAttributes); this.register(tref); } - lookup (tref: TypeRef): TypeRef | undefined; - lookup (trefs: Iterable): readonly TypeRef[] | undefined; - lookup (trefs: TypeRef | Iterable): TypeRef | readonly TypeRef[] | undefined { + public lookup(tref: TypeRef): TypeRef | undefined; + public lookup(trefs: Iterable): readonly TypeRef[] | undefined; + public lookup(trefs: TypeRef | Iterable): TypeRef | readonly TypeRef[] | undefined { assert(!this._wasUsed, "Cannot lookup constituents after building type"); if (isTypeRef(trefs)) { return this._typeBuilder.lookupTypeRefs([trefs], undefined, false); @@ -80,7 +72,7 @@ export class TypeReconstituter { } } - lookupMap(trefs: ReadonlyMap): ReadonlyMap | undefined { + public lookupMap(trefs: ReadonlyMap): ReadonlyMap | undefined { const resultValues = this.lookup(trefs.values()); if (resultValues === undefined) return undefined; assert(resultValues.length === trefs.size, "Didn't get back the correct number of types"); @@ -94,9 +86,9 @@ export class TypeReconstituter { return result; } - reconstitute (tref: TypeRef): TypeRef; - reconstitute (trefs: Iterable): readonly TypeRef[]; - reconstitute (trefs: TypeRef | Iterable): TypeRef | readonly TypeRef[] { + public reconstitute(tref: TypeRef): TypeRef; + public reconstitute(trefs: Iterable): readonly TypeRef[]; + public reconstitute(trefs: TypeRef | Iterable): TypeRef | readonly TypeRef[] { assert(this._wasUsed, "Cannot reconstitute constituents before building type"); if (isTypeRef(trefs)) { return this._typeBuilder.reconstituteTypeRef(trefs); @@ -105,68 +97,71 @@ export class TypeReconstituter { } } - reconstituteMap(trefs: ReadonlyMap): ReadonlyMap { + public reconstituteMap(trefs: ReadonlyMap): ReadonlyMap { return mapMap(trefs, tref => this._typeBuilder.reconstituteTypeRef(tref)); } - getPrimitiveType (kind: PrimitiveTypeKind): void { + public getPrimitiveType(kind: PrimitiveTypeKind): void { this.register(this.builderForNewType().getPrimitiveType(kind, this._typeAttributes, this._forwardingRef)); } - getEnumType (cases: ReadonlySet): void { + public getEnumType(cases: ReadonlySet): void { this.register(this.builderForNewType().getEnumType(this._typeAttributes, cases, this._forwardingRef)); } - getUniqueMapType (): void { + public getUniqueMapType(): void { this.registerAndAddAttributes(this.builderForNewType().getUniqueMapType(this._forwardingRef)); } - getMapType (values: TypeRef): void { + public getMapType(values: TypeRef): void { this.register(this.builderForNewType().getMapType(this._typeAttributes, values, this._forwardingRef)); } - getUniqueArrayType (): void { + public getUniqueArrayType(): void { this.registerAndAddAttributes(this.builderForNewType().getUniqueArrayType(this._forwardingRef)); } - getArrayType (items: TypeRef): void { + public getArrayType(items: TypeRef): void { this.register(this.builderForNewType().getArrayType(this._typeAttributes, items, this._forwardingRef)); } - setArrayItems (items: TypeRef): void { + public setArrayItems(items: TypeRef): void { this.builderForSetting().setArrayItems(this.getResult(), items); } - makeClassProperty (tref: TypeRef, isOptional: boolean): ClassProperty { + public makeClassProperty(tref: TypeRef, isOptional: boolean): ClassProperty { return this._typeBuilder.makeClassProperty(tref, isOptional); } - getObjectType (properties: ReadonlyMap, additionalProperties: TypeRef | undefined): void { + public getObjectType( + properties: ReadonlyMap, + additionalProperties: TypeRef | undefined + ): void { this.register( this.builderForNewType().getUniqueObjectType( this._typeAttributes, properties, additionalProperties, - this._forwardingRef, - ), + this._forwardingRef + ) ); } - getUniqueObjectType ( + public getUniqueObjectType( properties: ReadonlyMap | undefined, - additionalProperties: TypeRef | undefined, + additionalProperties: TypeRef | undefined ): void { this.register( this.builderForNewType().getUniqueObjectType( this._typeAttributes, properties, additionalProperties, - this._forwardingRef, - ), + this._forwardingRef + ) ); } - getClassType (properties: ReadonlyMap): void { + public getClassType(properties: ReadonlyMap): void { if (this._makeClassUnique) { this.getUniqueClassType(false, properties); return; @@ -175,40 +170,40 @@ export class TypeReconstituter { this.register(this.builderForNewType().getClassType(this._typeAttributes, properties, this._forwardingRef)); } - getUniqueClassType (isFixed: boolean, properties: ReadonlyMap | undefined): void { + public getUniqueClassType(isFixed: boolean, properties: ReadonlyMap | undefined): void { this.register( - this.builderForNewType().getUniqueClassType(this._typeAttributes, isFixed, properties, this._forwardingRef), + this.builderForNewType().getUniqueClassType(this._typeAttributes, isFixed, properties, this._forwardingRef) ); } - setObjectProperties ( + public setObjectProperties( properties: ReadonlyMap, - additionalProperties: TypeRef | undefined, + additionalProperties: TypeRef | undefined ): void { this.builderForSetting().setObjectProperties(this.getResult(), properties, additionalProperties); } - getUnionType (members: ReadonlySet): void { + public getUnionType(members: ReadonlySet): void { this.register(this.builderForNewType().getUnionType(this._typeAttributes, members, this._forwardingRef)); } - getUniqueUnionType (): void { + public getUniqueUnionType(): void { this.register( - this.builderForNewType().getUniqueUnionType(this._typeAttributes, undefined, this._forwardingRef), + this.builderForNewType().getUniqueUnionType(this._typeAttributes, undefined, this._forwardingRef) ); } - getIntersectionType (members: ReadonlySet): void { + public getIntersectionType(members: ReadonlySet): void { this.register(this.builderForNewType().getIntersectionType(this._typeAttributes, members, this._forwardingRef)); } - getUniqueIntersectionType (members?: ReadonlySet): void { + public getUniqueIntersectionType(members?: ReadonlySet): void { this.register( - this.builderForNewType().getUniqueIntersectionType(this._typeAttributes, members, this._forwardingRef), + this.builderForNewType().getUniqueIntersectionType(this._typeAttributes, members, this._forwardingRef) ); } - setSetOperationMembers (members: ReadonlySet): void { + public setSetOperationMembers(members: ReadonlySet): void { this.builderForSetting().setSetOperationMembers(this.getResult(), members); } } @@ -220,12 +215,12 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ private _printIndent = 0; - constructor ( - readonly originalGraph: TypeGraph, + public constructor( + protected readonly originalGraph: TypeGraph, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, graphHasProvenanceAttributes: boolean, - protected readonly debugPrint: boolean, + protected readonly debugPrint: boolean ) { super( originalGraph.serial + 1, @@ -233,13 +228,13 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ alphabetizeProperties, false, false, - graphHasProvenanceAttributes, + graphHasProvenanceAttributes ); } - withForwardingRef ( + public withForwardingRef( maybeForwardingRef: TypeRef | undefined, - typeCreator: (forwardingRef: TypeRef) => TypeRef, + typeCreator: (forwardingRef: TypeRef) => TypeRef ): TypeRef { if (maybeForwardingRef !== undefined) { return typeCreator(maybeForwardingRef); @@ -251,18 +246,26 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ return actualRef; } - reconstituteType (t: Type, attributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { + public reconstituteType(t: Type, attributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { return this.reconstituteTypeRef(t.typeRef, attributes, forwardingRef); } - abstract lookupTypeRefs (typeRefs: TypeRef[], forwardingRef?: TypeRef, replaceSet?: boolean): TypeRef | undefined; - protected abstract forceReconstituteTypeRef ( + public abstract lookupTypeRefs( + typeRefs: TypeRef[], + forwardingRef?: TypeRef, + replaceSet?: boolean + ): TypeRef | undefined; + protected abstract forceReconstituteTypeRef( originalRef: TypeRef, attributes?: TypeAttributes, maybeForwardingRef?: TypeRef ): TypeRef; - reconstituteTypeRef (originalRef: TypeRef, attributes?: TypeAttributes, maybeForwardingRef?: TypeRef): TypeRef { + public reconstituteTypeRef( + originalRef: TypeRef, + attributes?: TypeAttributes, + maybeForwardingRef?: TypeRef + ): TypeRef { const maybeRef = this.lookupTypeRefs([originalRef], maybeForwardingRef); if (maybeRef !== undefined) { if (attributes !== undefined) { @@ -275,11 +278,11 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ return this.forceReconstituteTypeRef(originalRef, attributes, maybeForwardingRef); } - reconstituteTypeAttributes (attributes: TypeAttributes): TypeAttributes { + public reconstituteTypeAttributes(attributes: TypeAttributes): TypeAttributes { return mapMap(attributes, (v, a) => a.reconstitute(this, v)); } - protected assertTypeRefsToReconstitute (typeRefs: TypeRef[], forwardingRef?: TypeRef): void { + protected assertTypeRefsToReconstitute(typeRefs: TypeRef[], forwardingRef?: TypeRef): void { assert(typeRefs.length > 0, "Must have at least one type to reconstitute"); for (const originalRef of typeRefs) { assertTypeRefGraph(originalRef, this.originalGraph); @@ -290,15 +293,15 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ } } - protected changeDebugPrintIndent (delta: number): void { + protected changeDebugPrintIndent(delta: number): void { this._printIndent += delta; } - protected get debugPrintIndentation (): string { + protected get debugPrintIndentation(): string { return indentationString(this._printIndent); } - finish (): TypeGraph { + public finish(): TypeGraph { for (const [name, t] of this.originalGraph.topLevels) { this.addTopLevel(name, this.reconstituteType(t)); } @@ -306,11 +309,11 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ return super.finish(); } - setLostTypeAttributes (): void { + public setLostTypeAttributes(): void { this._lostTypeAttributes = true; } - get lostTypeAttributes (): boolean { + public get lostTypeAttributes(): boolean { return this._lostTypeAttributes; } } @@ -318,20 +321,20 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { private readonly _attributeSources: Map = new Map(); - constructor ( + public constructor( originalGraph: TypeGraph, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, graphHasProvenanceAttributes: boolean, private readonly _map: ReadonlyMap, - debugPrintRemapping: boolean, + debugPrintRemapping: boolean ) { super( originalGraph, stringTypeMapping, alphabetizeProperties, graphHasProvenanceAttributes, - debugPrintRemapping, + debugPrintRemapping ); for (const [source, target] of _map) { @@ -345,22 +348,22 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { } } - protected makeIdentity (_maker: () => MaybeTypeIdentity): MaybeTypeIdentity { + protected makeIdentity(_maker: () => MaybeTypeIdentity): MaybeTypeIdentity { return undefined; } - private getMapTarget (tref: TypeRef): TypeRef { + private getMapTarget(tref: TypeRef): TypeRef { const maybeType = this._map.get(derefTypeRef(tref, this.originalGraph)); if (maybeType === undefined) return tref; assert(this._map.get(maybeType) === undefined, "We have a type that's remapped to a remapped type"); return maybeType.typeRef; } - protected addForwardingIntersection (_forwardingRef: TypeRef, _tref: TypeRef): TypeRef { + protected addForwardingIntersection(_forwardingRef: TypeRef, _tref: TypeRef): TypeRef { return panic("We can't add forwarding intersections when we're removing forwarding intersections"); } - lookupTypeRefs (typeRefs: TypeRef[], forwardingRef?: TypeRef): TypeRef | undefined { + public lookupTypeRefs(typeRefs: TypeRef[], forwardingRef?: TypeRef): TypeRef | undefined { assert(forwardingRef === undefined, "We can't have a forwarding ref when we remap"); this.assertTypeRefsToReconstitute(typeRefs, forwardingRef); @@ -376,10 +379,10 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { return first; } - protected forceReconstituteTypeRef ( + protected forceReconstituteTypeRef( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef, + maybeForwardingRef?: TypeRef ): TypeRef { originalRef = this.getMapTarget(originalRef); @@ -407,13 +410,13 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { attributes = combineTypeAttributes( "union", attributes, - this.reconstituteTypeAttributes(originalAttributes), + this.reconstituteTypeAttributes(originalAttributes) ); } else { attributes = combineTypeAttributes( "union", attributes, - this.reconstituteTypeAttributes(combineTypeAttributesOfTypes("union", attributeSources)), + this.reconstituteTypeAttributes(combineTypeAttributesOfTypes("union", attributeSources)) ); } @@ -430,7 +433,7 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { this.changeDebugPrintIndent(-1); console.log(`${this.debugPrintIndentation}reconstituted ${index} as ${typeRefIndex(tref)}`); } - }, + } ); originalType.reconstitute(reconstituter, this.canonicalOrder); return reconstituter.getResult(); @@ -443,7 +446,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder private readonly _reconstitutedUnions: EqualityMap, TypeRef> = new EqualityMap(); - constructor ( + public constructor( originalGraph: TypeGraph, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, @@ -454,14 +457,14 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder typesToReplace: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef - ) => TypeRef, + ) => TypeRef ) { super( originalGraph, stringTypeMapping, alphabetizeProperties, graphHasProvenanceAttributes, - debugPrintReconstitution, + debugPrintReconstitution ); this._setsToReplaceByMember = new Map(); @@ -475,19 +478,19 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder } } - registerUnion (typeRefs: TypeRef[], reconstituted: TypeRef): void { + public registerUnion(typeRefs: TypeRef[], reconstituted: TypeRef): void { const set = new Set(typeRefs); assert(!this._reconstitutedUnions.has(set), "Cannot register reconstituted set twice"); this._reconstitutedUnions.set(set, reconstituted); } - private replaceSet (typesToReplace: ReadonlySet, maybeForwardingRef: TypeRef | undefined): TypeRef { + private replaceSet(typesToReplace: ReadonlySet, maybeForwardingRef: TypeRef | undefined): TypeRef { return this.withForwardingRef(maybeForwardingRef, forwardingRef => { if (this.debugPrint) { console.log( `${this.debugPrintIndentation}replacing set ${Array.from(typesToReplace) .map(t => t.index.toString()) - .join(",")} as ${typeRefIndex(forwardingRef)}`, + .join(",")} as ${typeRefIndex(forwardingRef)}` ); this.changeDebugPrintIndent(1); } @@ -507,7 +510,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder console.log( `${this.debugPrintIndentation}replaced set ${Array.from(typesToReplace) .map(t => t.index.toString()) - .join(",")} as ${typeRefIndex(forwardingRef)}`, + .join(",")} as ${typeRefIndex(forwardingRef)}` ); } @@ -515,10 +518,10 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder }); } - protected forceReconstituteTypeRef ( + protected forceReconstituteTypeRef( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef, + maybeForwardingRef?: TypeRef ): TypeRef { const [originalType, originalAttributes] = typeAndAttributesForTypeRef(originalRef, this.originalGraph); const index = typeRefIndex(originalRef); @@ -534,7 +537,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder attributes = combineTypeAttributes( "union", attributes, - this.reconstituteTypeAttributes(originalAttributes), + this.reconstituteTypeAttributes(originalAttributes) ); } @@ -560,7 +563,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder } /* - reconstituteTypeUnmodified(originalType: Type): TypeRef { + public reconstituteTypeUnmodified(originalType: Type): TypeRef { const reconstituter = new TypeReconstituter( this, this.alphabetizeProperties, @@ -575,7 +578,7 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder // If the union of these type refs have been, or are supposed to be, reconstituted to // one target type, return it. Otherwise return undefined. - lookupTypeRefs (typeRefs: TypeRef[], forwardingRef?: TypeRef, replaceSet = true): TypeRef | undefined { + public lookupTypeRefs(typeRefs: TypeRef[], forwardingRef?: TypeRef, replaceSet = true): TypeRef | undefined { this.assertTypeRefsToReconstitute(typeRefs, forwardingRef); // Check whether we have already reconstituted them. That means ensuring diff --git a/packages/quicktype-core/src/MakeTransformations.ts b/packages/quicktype-core/src/MakeTransformations.ts index 0b98b390f..8daede47e 100644 --- a/packages/quicktype-core/src/MakeTransformations.ts +++ b/packages/quicktype-core/src/MakeTransformations.ts @@ -1,26 +1,20 @@ import { setFilter, iterableFirst, mapMapEntries, withDefault, iterableSome, arraySortByInto } from "collection-utils"; -import { type TypeGraph, type TypeRef} from "./TypeGraph"; +import { type TypeGraph, type TypeRef } from "./TypeGraph"; import { typeRefIndex } from "./TypeGraph"; import { type TargetLanguage } from "./TargetLanguage"; -import { - type TypeKind, - type Type, - type PrimitiveType, - type PrimitiveStringTypeKind, -} from "./Type"; +import { type TypeKind, type Type, type PrimitiveType, type PrimitiveStringTypeKind } from "./Type"; import { UnionType, EnumType, ArrayType, isNumberTypeKind, isPrimitiveStringTypeKind, - targetTypeKindForTransformedStringTypeKind, + targetTypeKindForTransformedStringTypeKind } from "./Type"; import { type GraphRewriteBuilder } from "./GraphRewriting"; import { defined, assert, panic } from "./support/Support"; -import { - type Transformer} from "./Transformers"; +import { type Transformer } from "./Transformers"; import { UnionInstantiationTransformer, DecodingChoiceTransformer, @@ -33,19 +27,19 @@ import { ParseStringTransformer, ArrayDecodingTransformer, MinMaxLengthCheckTransformer, - MinMaxValueTransformer, + MinMaxValueTransformer } from "./Transformers"; -import { type TypeAttributes} from "./attributes/TypeAttributes"; +import { type TypeAttributes } from "./attributes/TypeAttributes"; import { emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; import { StringTypes } from "./attributes/StringTypes"; import { type RunContext } from "./Run"; import { minMaxLengthForType, minMaxValueForType } from "./attributes/Constraints"; -function transformationAttributes ( +function transformationAttributes( graph: TypeGraph, reconstitutedTargetType: TypeRef, transformer: Transformer, - debugPrintTransformations: boolean, + debugPrintTransformations: boolean ): TypeAttributes { const transformation = new Transformation(graph, reconstitutedTargetType, transformer); if (debugPrintTransformations) { @@ -58,11 +52,11 @@ function transformationAttributes ( return transformationTypeAttributeKind.makeAttributes(transformation); } -function makeEnumTransformer ( +function makeEnumTransformer( graph: TypeGraph, enumType: EnumType, stringType: TypeRef, - continuation?: Transformer, + continuation?: Transformer ): Transformer { const sortedCases = Array.from(enumType.cases).sort(); const caseTransformers = sortedCases.map( @@ -71,18 +65,18 @@ function makeEnumTransformer ( graph, stringType, new StringProducerTransformer(graph, stringType, continuation, c), - c, - ), + c + ) ); return new ChoiceTransformer(graph, stringType, caseTransformers); } -function replaceUnion ( +function replaceUnion( union: UnionType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, transformedTypes: Set, - debugPrintTransformations: boolean, + debugPrintTransformations: boolean ): TypeRef { const graph = builder.typeGraph; @@ -91,7 +85,7 @@ function replaceUnion ( // Type attributes that we lost during reconstitution. let additionalAttributes = emptyTypeAttributes; - function reconstituteMember (t: Type): TypeRef { + function reconstituteMember(t: Type): TypeRef { // Special handling for some transformed string type kinds: The type in // the union must be the target type, so if one already exists, use that // one, otherwise make a new one. @@ -123,16 +117,16 @@ function replaceUnion ( ? builder.getUnionType(union.getAttributes(), reconstitutedMemberSet) : defined(iterableFirst(reconstitutedMemberSet)); - function memberForKind (kind: TypeKind) { + function memberForKind(kind: TypeKind) { return defined(reconstitutedMembersByKind.get(kind)); } - function consumer (memberTypeRef: TypeRef): Transformer | undefined { + function consumer(memberTypeRef: TypeRef): Transformer | undefined { if (!haveUnion) return undefined; return new UnionInstantiationTransformer(graph, memberTypeRef); } - function transformerForKind (kind: TypeKind) { + function transformerForKind(kind: TypeKind) { const member = union.findMember(kind); if (member === undefined) return undefined; const memberTypeRef = memberForKind(kind); @@ -140,7 +134,7 @@ function replaceUnion ( } let maybeStringType: TypeRef | undefined = undefined; - function getStringType (): TypeRef { + function getStringType(): TypeRef { if (maybeStringType === undefined) { maybeStringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); } @@ -148,7 +142,7 @@ function replaceUnion ( return maybeStringType; } - function transformerForStringType (t: Type): Transformer | undefined { + function transformerForStringType(t: Type): Transformer | undefined { const memberRef = memberForKind(t.kind); if (t.kind === "string") { const minMax = minMaxLengthForType(t); @@ -179,8 +173,8 @@ function replaceUnion ( new ChoiceTransformer( graph, getStringType(), - stringTypes.map(t => defined(transformerForStringType(t))), - ), + stringTypes.map(t => defined(transformerForStringType(t))) + ) ); } @@ -188,7 +182,7 @@ function replaceUnion ( const transformerForMap = transformerForKind("map"); assert( transformerForClass === undefined || transformerForMap === undefined, - "Can't have both class and map in a transformed union", + "Can't have both class and map in a transformed union" ); const transformerForObject = transformerForClass !== undefined ? transformerForClass : transformerForMap; @@ -201,21 +195,21 @@ function replaceUnion ( transformerForKind("bool"), transformerForString, transformerForKind("array"), - transformerForObject, + transformerForObject ); const attributes = transformationAttributes(graph, reconstitutedTargetType, transformer, debugPrintTransformations); return builder.getPrimitiveType( "any", combineTypeAttributes("union", attributes, additionalAttributes), - forwardingRef, + forwardingRef ); } -function replaceArray ( +function replaceArray( arrayType: ArrayType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean, + debugPrintTransformations: boolean ): TypeRef { const anyType = builder.getPrimitiveType("any"); const anyArrayType = builder.getArrayType(emptyTypeAttributes, anyType); @@ -225,74 +219,74 @@ function replaceArray ( anyArrayType, undefined, reconstitutedItems, - new DecodingTransformer(builder.typeGraph, anyType, undefined), + new DecodingTransformer(builder.typeGraph, anyType, undefined) ); const reconstitutedArray = builder.getArrayType( builder.reconstituteTypeAttributes(arrayType.getAttributes()), - reconstitutedItems, + reconstitutedItems ); const attributes = transformationAttributes( builder.typeGraph, reconstitutedArray, transformer, - debugPrintTransformations, + debugPrintTransformations ); return builder.getArrayType(attributes, anyType, forwardingRef); } -function replaceEnum ( +function replaceEnum( enumType: EnumType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean, + debugPrintTransformations: boolean ): TypeRef { const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); const transformer = new DecodingTransformer( builder.typeGraph, stringType, - makeEnumTransformer(builder.typeGraph, enumType, stringType), + makeEnumTransformer(builder.typeGraph, enumType, stringType) ); const reconstitutedEnum = builder.getEnumType(enumType.getAttributes(), enumType.cases); const attributes = transformationAttributes( builder.typeGraph, reconstitutedEnum, transformer, - debugPrintTransformations, + debugPrintTransformations ); return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } -function replaceNumber ( +function replaceNumber( t: PrimitiveType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean, + debugPrintTransformations: boolean ): TypeRef { const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); const [min, max] = defined(minMaxValueForType(t)); const transformer = new DecodingTransformer( builder.typeGraph, stringType, - new MinMaxValueTransformer(builder.typeGraph, stringType, undefined, min, max), + new MinMaxValueTransformer(builder.typeGraph, stringType, undefined, min, max) ); const reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); const attributes = transformationAttributes( builder.typeGraph, builder.getPrimitiveType("double", reconstitutedAttributes, undefined), transformer, - debugPrintTransformations, + debugPrintTransformations ); return builder.getPrimitiveType("double", attributes, forwardingRef); } -function replaceString ( +function replaceString( t: PrimitiveType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean, + debugPrintTransformations: boolean ): TypeRef { const [min, max] = defined(minMaxLengthForType(t)); const reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); @@ -300,23 +294,23 @@ function replaceString ( const transformer = new DecodingTransformer( builder.typeGraph, stringType, - new MinMaxLengthCheckTransformer(builder.typeGraph, stringType, undefined, min, max), + new MinMaxLengthCheckTransformer(builder.typeGraph, stringType, undefined, min, max) ); const attributes = transformationAttributes( builder.typeGraph, builder.getStringType(reconstitutedAttributes, undefined), transformer, - debugPrintTransformations, + debugPrintTransformations ); return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } -function replaceTransformedStringType ( +function replaceTransformedStringType( t: PrimitiveType, kind: PrimitiveStringTypeKind, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean, + debugPrintTransformations: boolean ): TypeRef { const reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); const targetTypeKind = withDefault(targetTypeKindForTransformedStringTypeKind(kind), kind); @@ -324,18 +318,18 @@ function replaceTransformedStringType ( const transformer = new DecodingTransformer( builder.typeGraph, stringType, - new ParseStringTransformer(builder.typeGraph, stringType, undefined), + new ParseStringTransformer(builder.typeGraph, stringType, undefined) ); const attributes = transformationAttributes( builder.typeGraph, builder.getPrimitiveType(targetTypeKind, reconstitutedAttributes), transformer, - debugPrintTransformations, + debugPrintTransformations ); return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } -export function makeTransformations (ctx: RunContext, graph: TypeGraph, targetLanguage: TargetLanguage): TypeGraph { +export function makeTransformations(ctx: RunContext, graph: TypeGraph, targetLanguage: TargetLanguage): TypeGraph { const transformedTypes = setFilter(graph.allTypesUnordered(), t => { if (targetLanguage.needsTransformerForType(t)) return true; if (!(t instanceof UnionType)) return false; @@ -344,10 +338,10 @@ export function makeTransformations (ctx: RunContext, graph: TypeGraph, targetLa return iterableSome(stringMembers, m => targetLanguage.needsTransformerForType(m)); }); - function replace ( + function replace( setOfOneUnion: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef, + forwardingRef: TypeRef ): TypeRef { const t = defined(iterableFirst(setOfOneUnion)); if (t instanceof UnionType) { @@ -376,7 +370,7 @@ export function makeTransformations (ctx: RunContext, graph: TypeGraph, targetLa t.kind, builder, forwardingRef, - ctx.debugPrintTransformations, + ctx.debugPrintTransformations ); } @@ -390,6 +384,6 @@ export function makeTransformations (ctx: RunContext, graph: TypeGraph, targetLa false, groups, ctx.debugPrintReconstitution, - replace, + replace ); } diff --git a/packages/quicktype-core/src/MarkovChain.ts b/packages/quicktype-core/src/MarkovChain.ts index 85bd62b4d..a2e6f453b 100644 --- a/packages/quicktype-core/src/MarkovChain.ts +++ b/packages/quicktype-core/src/MarkovChain.ts @@ -13,7 +13,7 @@ export interface MarkovChain { trie: Trie; } -function makeTrie (): Trie { +function makeTrie(): Trie { const arr: SubTrie[] = []; for (let i = 0; i < 128; i++) { arr.push(null); @@ -22,7 +22,7 @@ function makeTrie (): Trie { return { count: 0, arr }; } -function lookup (t: Trie, seq: string, i: number): Trie | number | undefined { +function lookup(t: Trie, seq: string, i: number): Trie | number | undefined { if (i >= seq.length) { return t; } @@ -44,7 +44,7 @@ function lookup (t: Trie, seq: string, i: number): Trie | number | undefined { } } -function increment (t: Trie, seq: string, i: number): void { +function increment(t: Trie, seq: string, i: number): void { let first = seq.charCodeAt(i); if (first >= 128) { first = 0; @@ -79,7 +79,7 @@ function increment (t: Trie, seq: string, i: number): void { increment(st, seq, i + 1); } -export function train (lines: string[], depth: number): MarkovChain { +export function train(lines: string[], depth: number): MarkovChain { const trie = makeTrie(); for (const l of lines) { for (let i = depth; i <= l.length; i++) { @@ -90,11 +90,11 @@ export function train (lines: string[], depth: number): MarkovChain { return { trie, depth }; } -export function load (): MarkovChain { +export function load(): MarkovChain { return JSON.parse(inflateBase64(encodedMarkovChain)); } -export function evaluateFull (mc: MarkovChain, word: string): [number, number[]] { +export function evaluateFull(mc: MarkovChain, word: string): [number, number[]] { const { trie, depth } = mc; if (word.length < depth) { return [1, []]; @@ -119,16 +119,16 @@ export function evaluateFull (mc: MarkovChain, word: string): [number, number[]] return [Math.pow(p, 1 / (word.length - depth + 1)), scores]; } -export function evaluate (mc: MarkovChain, word: string): number { +export function evaluate(mc: MarkovChain, word: string): number { return evaluateFull(mc, word)[0]; } -function randomInt (lower: number, upper: number) { +function randomInt(lower: number, upper: number) { const range = upper - lower; return lower + Math.floor(Math.random() * range); } -export function generate (mc: MarkovChain, state: string, unseenWeight: number): string { +export function generate(mc: MarkovChain, state: string, unseenWeight: number): string { assert(state.length === mc.depth - 1, "State and chain length don't match up"); const t = lookup(mc.trie, state, 0); if (typeof t === "number") { @@ -139,7 +139,7 @@ export function generate (mc: MarkovChain, state: string, unseenWeight: number): return String.fromCharCode(randomInt(32, 127)); } - const counts = t.arr.map((x, i) => x === null ? i === 0 ? 0 : unseenWeight : (x as number)); + const counts = t.arr.map((x, i) => (x === null ? (i === 0 ? 0 : unseenWeight) : (x as number))); let n = 0; for (const c of counts) { n += c; @@ -157,11 +157,11 @@ export function generate (mc: MarkovChain, state: string, unseenWeight: number): return panic("We screwed up bookkeeping, or randomInt"); } -function testWord (mc: MarkovChain, word: string): void { +function testWord(mc: MarkovChain, word: string): void { console.log(`"${word}": ${evaluate(mc, word)}`); } -export function test (): void { +export function test(): void { const mc = load(); testWord(mc, "url"); @@ -185,6 +185,6 @@ export function test (): void { testWord( mc, - "\ud83d\udebe \ud83c\udd92 \ud83c\udd93 \ud83c\udd95 \ud83c\udd96 \ud83c\udd97 \ud83c\udd99 \ud83c\udfe7", + "\ud83d\udebe \ud83c\udd92 \ud83c\udd93 \ud83c\udd95 \ud83c\udd96 \ud83c\udd97 \ud83c\udd99 \ud83c\udfe7" ); } diff --git a/packages/quicktype-core/src/Messages.ts b/packages/quicktype-core/src/Messages.ts index 082c3ce40..0236235f9 100644 --- a/packages/quicktype-core/src/Messages.ts +++ b/packages/quicktype-core/src/Messages.ts @@ -2,84 +2,84 @@ import { type StringMap } from "./support/Support"; import { type Ref } from "./input/JSONSchemaInput"; export type ErrorProperties = - | { kind: "InternalError", properties: { message: string, }, } + | { kind: "InternalError"; properties: { message: string } } // Misc | { - kind: "MiscJSONParseError", - properties: { address: string, description: string, message: string, }, - } - | { kind: "MiscReadError", properties: { fileOrURL: string, message: string, }, } - | { kind: "MiscUnicodeHighSurrogateWithoutLowSurrogate", properties: {}, } - | { kind: "MiscInvalidMinMaxConstraint", properties: { max: number, min: number, }, } + kind: "MiscJSONParseError"; + properties: { address: string; description: string; message: string }; + } + | { kind: "MiscReadError"; properties: { fileOrURL: string; message: string } } + | { kind: "MiscUnicodeHighSurrogateWithoutLowSurrogate"; properties: {} } + | { kind: "MiscInvalidMinMaxConstraint"; properties: { max: number; min: number } } // Inference - | { kind: "InferenceJSONReferenceNotRooted", properties: { reference: string, }, } - | { kind: "InferenceJSONReferenceToUnion", properties: { reference: string, }, } - | { kind: "InferenceJSONReferenceWrongProperty", properties: { reference: string, }, } - | { kind: "InferenceJSONReferenceInvalidArrayIndex", properties: { reference: string, }, } + | { kind: "InferenceJSONReferenceNotRooted"; properties: { reference: string } } + | { kind: "InferenceJSONReferenceToUnion"; properties: { reference: string } } + | { kind: "InferenceJSONReferenceWrongProperty"; properties: { reference: string } } + | { kind: "InferenceJSONReferenceInvalidArrayIndex"; properties: { reference: string } } // JSON Schema input - | { kind: "SchemaArrayIsInvalidSchema", properties: { ref: Ref, }, } - | { kind: "SchemaNullIsInvalidSchema", properties: { ref: Ref, }, } - | { kind: "SchemaRefMustBeString", properties: { actual: string, ref: Ref, }, } - | { kind: "SchemaAdditionalTypesForbidRequired", properties: { ref: Ref, }, } - | { kind: "SchemaNoTypeSpecified", properties: { ref: Ref, }, } - | { kind: "SchemaInvalidType", properties: { ref: Ref, type: string, }, } - | { kind: "SchemaFalseNotSupported", properties: { ref: Ref, }, } - | { kind: "SchemaInvalidJSONSchemaType", properties: { ref: Ref, type: string, }, } - | { kind: "SchemaRequiredMustBeStringOrStringArray", properties: { actual: any, ref: Ref, }, } - | { kind: "SchemaRequiredElementMustBeString", properties: { element: any, ref: Ref, }, } - | { kind: "SchemaTypeMustBeStringOrStringArray", properties: { actual: any, }, } - | { kind: "SchemaTypeElementMustBeString", properties: { element: any, ref: Ref, }, } - | { kind: "SchemaArrayItemsMustBeStringOrArray", properties: { actual: any, ref: Ref, }, } - | { kind: "SchemaIDMustHaveAddress", properties: { id: string, ref: Ref, }, } - | { kind: "SchemaWrongAccessorEntryArrayLength", properties: { operation: string, ref: Ref, }, } + | { kind: "SchemaArrayIsInvalidSchema"; properties: { ref: Ref } } + | { kind: "SchemaNullIsInvalidSchema"; properties: { ref: Ref } } + | { kind: "SchemaRefMustBeString"; properties: { actual: string; ref: Ref } } + | { kind: "SchemaAdditionalTypesForbidRequired"; properties: { ref: Ref } } + | { kind: "SchemaNoTypeSpecified"; properties: { ref: Ref } } + | { kind: "SchemaInvalidType"; properties: { ref: Ref; type: string } } + | { kind: "SchemaFalseNotSupported"; properties: { ref: Ref } } + | { kind: "SchemaInvalidJSONSchemaType"; properties: { ref: Ref; type: string } } + | { kind: "SchemaRequiredMustBeStringOrStringArray"; properties: { actual: any; ref: Ref } } + | { kind: "SchemaRequiredElementMustBeString"; properties: { element: any; ref: Ref } } + | { kind: "SchemaTypeMustBeStringOrStringArray"; properties: { actual: any } } + | { kind: "SchemaTypeElementMustBeString"; properties: { element: any; ref: Ref } } + | { kind: "SchemaArrayItemsMustBeStringOrArray"; properties: { actual: any; ref: Ref } } + | { kind: "SchemaIDMustHaveAddress"; properties: { id: string; ref: Ref } } + | { kind: "SchemaWrongAccessorEntryArrayLength"; properties: { operation: string; ref: Ref } } | { - kind: "SchemaSetOperationCasesIsNotArray", - properties: { cases: any, operation: string, ref: Ref, }, - } - | { kind: "SchemaMoreThanOneUnionMemberName", properties: { names: string[], }, } - | { kind: "SchemaCannotGetTypesFromBoolean", properties: { ref: string, }, } - | { kind: "SchemaCannotIndexArrayWithNonNumber", properties: { actual: string, ref: Ref, }, } - | { kind: "SchemaIndexNotInArray", properties: { index: number, ref: Ref, }, } - | { kind: "SchemaKeyNotInObject", properties: { key: string, ref: Ref, }, } - | { kind: "SchemaFetchError", properties: { address: string, base: Ref, }, } - | { kind: "SchemaFetchErrorTopLevel", properties: { address: string, }, } - | { kind: "SchemaFetchErrorAdditional", properties: { address: string, }, } + kind: "SchemaSetOperationCasesIsNotArray"; + properties: { cases: any; operation: string; ref: Ref }; + } + | { kind: "SchemaMoreThanOneUnionMemberName"; properties: { names: string[] } } + | { kind: "SchemaCannotGetTypesFromBoolean"; properties: { ref: string } } + | { kind: "SchemaCannotIndexArrayWithNonNumber"; properties: { actual: string; ref: Ref } } + | { kind: "SchemaIndexNotInArray"; properties: { index: number; ref: Ref } } + | { kind: "SchemaKeyNotInObject"; properties: { key: string; ref: Ref } } + | { kind: "SchemaFetchError"; properties: { address: string; base: Ref } } + | { kind: "SchemaFetchErrorTopLevel"; properties: { address: string } } + | { kind: "SchemaFetchErrorAdditional"; properties: { address: string } } // GraphQL input - | { kind: "GraphQLNoQueriesDefined", properties: {}, } + | { kind: "GraphQLNoQueriesDefined"; properties: {} } // Driver - | { kind: "DriverUnknownSourceLanguage", properties: { lang: string, }, } - | { kind: "DriverUnknownOutputLanguage", properties: { lang: string, }, } - | { kind: "DriverMoreThanOneInputGiven", properties: { topLevel: string, }, } - | { kind: "DriverCannotInferNameForSchema", properties: { uri: string, }, } - | { kind: "DriverNoGraphQLQueryGiven", properties: {}, } - | { kind: "DriverNoGraphQLSchemaInDir", properties: { dir: string, }, } - | { kind: "DriverMoreThanOneGraphQLSchemaInDir", properties: { dir: string, }, } - | { kind: "DriverSourceLangMustBeGraphQL", properties: {}, } - | { kind: "DriverGraphQLSchemaNeeded", properties: {}, } - | { kind: "DriverInputFileDoesNotExist", properties: { filename: string, }, } - | { kind: "DriverCannotMixJSONWithOtherSamples", properties: { dir: string, }, } - | { kind: "DriverCannotMixNonJSONInputs", properties: { dir: string, }, } - | { kind: "DriverUnknownDebugOption", properties: { option: string, }, } - | { kind: "DriverNoLanguageOrExtension", properties: {}, } - | { kind: "DriverCLIOptionParsingFailed", properties: { message: string, }, } + | { kind: "DriverUnknownSourceLanguage"; properties: { lang: string } } + | { kind: "DriverUnknownOutputLanguage"; properties: { lang: string } } + | { kind: "DriverMoreThanOneInputGiven"; properties: { topLevel: string } } + | { kind: "DriverCannotInferNameForSchema"; properties: { uri: string } } + | { kind: "DriverNoGraphQLQueryGiven"; properties: {} } + | { kind: "DriverNoGraphQLSchemaInDir"; properties: { dir: string } } + | { kind: "DriverMoreThanOneGraphQLSchemaInDir"; properties: { dir: string } } + | { kind: "DriverSourceLangMustBeGraphQL"; properties: {} } + | { kind: "DriverGraphQLSchemaNeeded"; properties: {} } + | { kind: "DriverInputFileDoesNotExist"; properties: { filename: string } } + | { kind: "DriverCannotMixJSONWithOtherSamples"; properties: { dir: string } } + | { kind: "DriverCannotMixNonJSONInputs"; properties: { dir: string } } + | { kind: "DriverUnknownDebugOption"; properties: { option: string } } + | { kind: "DriverNoLanguageOrExtension"; properties: {} } + | { kind: "DriverCLIOptionParsingFailed"; properties: { message: string } } // IR - | { kind: "IRNoForwardDeclarableTypeInCycle", properties: {}, } - | { kind: "IRTypeAttributesNotPropagated", properties: { count: number, indexes: number[], }, } - | { kind: "IRNoEmptyUnions", properties: {}, } + | { kind: "IRNoForwardDeclarableTypeInCycle"; properties: {} } + | { kind: "IRTypeAttributesNotPropagated"; properties: { count: number; indexes: number[] } } + | { kind: "IRNoEmptyUnions"; properties: {} } // Rendering - | { kind: "RendererUnknownOptionValue", properties: { name: string, value: string, }, } + | { kind: "RendererUnknownOptionValue"; properties: { name: string; value: string } } // TypeScript input - | { kind: "TypeScriptCompilerError", properties: { message: string, }, }; + | { kind: "TypeScriptCompilerError"; properties: { message: string } }; -export type ErrorKinds = ErrorProperties extends { kind: infer K, } ? K : never; +export type ErrorKinds = ErrorProperties extends { kind: infer K } ? K : never; type ErrorMessages = { readonly [K in ErrorKinds]: string }; @@ -106,7 +106,7 @@ const errorMessages: ErrorMessages = { "Can't have non-specified required properties but forbidden additionalTypes at ${ref}", SchemaNoTypeSpecified: "JSON Schema must specify at least one type at ${ref}", SchemaInvalidType: "Invalid type ${type} in JSON Schema at ${ref}", - SchemaFalseNotSupported: "Schema \"false\" is not supported at ${ref}", + SchemaFalseNotSupported: 'Schema "false" is not supported at ${ref}', SchemaInvalidJSONSchemaType: "Value of type ${type} is not valid JSON Schema at ${ref}", SchemaRequiredMustBeStringOrStringArray: "`required` must be string or array of strings, but is ${actual} at ${ref}", @@ -161,25 +161,24 @@ const errorMessages: ErrorMessages = { RendererUnknownOptionValue: "Unknown value ${value} for option ${name}", // TypeScript input - TypeScriptCompilerError: "TypeScript error: ${message}", + TypeScriptCompilerError: "TypeScript error: ${message}" }; -export type ErrorPropertiesForName = Extract extends { properties: infer P, } - ? P - : never; +export type ErrorPropertiesForName = + Extract extends { properties: infer P } ? P : never; export class QuickTypeError extends Error { - constructor ( - readonly errorMessage: string, - readonly messageName: string, - userMessage: string, - readonly properties: StringMap, + public constructor( + public readonly errorMessage: string, + public readonly messageName: string, + public userMessage: string, + public readonly properties: StringMap ) { super(userMessage); } } -export function messageError (kind: N, properties: ErrorPropertiesForName): never { +export function messageError(kind: N, properties: ErrorPropertiesForName): never { const message = errorMessages[kind]; let userMessage: string = message; const propertiesMap = properties as StringMap; @@ -200,10 +199,10 @@ export function messageError (kind: N, properties: ErrorPr throw new QuickTypeError(message, kind, userMessage, propertiesMap); } -export function messageAssert ( +export function messageAssert( assertion: boolean, kind: N, - properties: ErrorPropertiesForName, + properties: ErrorPropertiesForName ): void { if (assertion) return; return messageError(kind, properties); diff --git a/packages/quicktype-core/src/Naming.ts b/packages/quicktype-core/src/Naming.ts index 819163748..f49ad815b 100644 --- a/packages/quicktype-core/src/Naming.ts +++ b/packages/quicktype-core/src/Naming.ts @@ -10,25 +10,25 @@ import { setFilterMap, iterableFirst, iterableEvery, - mapMergeInto, + mapMergeInto } from "collection-utils"; import { defined, assert, panic } from "./support/Support"; export class Namespace { - readonly forbiddenNamespaces: ReadonlySet; + public readonly forbiddenNamespaces: ReadonlySet; - readonly additionalForbidden: ReadonlySet; + public readonly additionalForbidden: ReadonlySet; private readonly _children = new Set(); private readonly _members = new Set(); - constructor ( + public constructor( _name: string, parent: Namespace | undefined, forbiddenNamespaces: Iterable, - additionalForbidden: Iterable, + additionalForbidden: Iterable ) { this.forbiddenNamespaces = new Set(forbiddenNamespaces); this.additionalForbidden = new Set(additionalForbidden); @@ -37,24 +37,24 @@ export class Namespace { } } - private addChild (child: Namespace): void { + private addChild(child: Namespace): void { this._children.add(child); } - get children (): ReadonlySet { + public get children(): ReadonlySet { return this._children; } - get members (): ReadonlySet { + public get members(): ReadonlySet { return this._members; } - get forbiddenNameds (): ReadonlySet { + public get forbiddenNameds(): ReadonlySet { // FIXME: cache return setUnion(this.additionalForbidden, ...Array.from(this.forbiddenNamespaces).map(ns => ns.members)); } - add(named: TName): TName { + public add(named: TName): TName { this._members.add(named); return named; } @@ -80,16 +80,20 @@ export type NameStyle = (rawName: string) => string; export class Namer { private readonly _prefixes: ReadonlySet; - constructor (readonly name: string, readonly nameStyle: NameStyle, prefixes: string[]) { + public constructor( + public readonly name: string, + public readonly nameStyle: NameStyle, + public prefixes: string[] + ) { this._prefixes = new Set(prefixes); } // The namesIterable comes directly out of the context and will // be modified if we assign - assignNames ( + public assignNames( names: ReadonlyMap, forbiddenNamesIterable: Iterable, - namesToAssignIterable: Iterable, + namesToAssignIterable: Iterable ): ReadonlyMap { const forbiddenNames = new Set(forbiddenNamesIterable); const namesToAssign = Array.from(namesToAssignIterable); @@ -108,7 +112,7 @@ export class Namer { proposedNames, proposed => !forbiddenNames.has(namingFunction.nameStyle(proposed)) && - namesToAssign.every(n => n === name || !n.proposeUnstyledNames(names).has(proposed)), + namesToAssign.every(n => n === name || !n.proposeUnstyledNames(names).has(proposed)) ); if (maybeUniqueName !== undefined) { const styledName = namingFunction.nameStyle(maybeUniqueName); @@ -165,10 +169,10 @@ const funPrefixes = [ "Magenta", "Frisky", "Mischievous", - "Braggadocious", + "Braggadocious" ]; -export function funPrefixNamer (name: string, nameStyle: NameStyle): Namer { +export function funPrefixNamer(name: string, nameStyle: NameStyle): Namer { return new Namer(name, nameStyle, funPrefixes); } @@ -181,30 +185,36 @@ export abstract class Name { private readonly _associates = new Set(); // If a Named is fixed, the namingFunction is undefined. - constructor (private readonly _namingFunction: Namer | undefined, readonly order: number) {} + public constructor( + private readonly _namingFunction: Namer | undefined, + public readonly order: number + ) {} - addAssociate (associate: AssociatedName): void { + public addAssociate(associate: AssociatedName): void { this._associates.add(associate); } - abstract get dependencies (): readonly Name[]; + public abstract get dependencies(): readonly Name[]; - isFixed (): this is FixedName { + public isFixed(): this is FixedName { return this instanceof FixedName; } - get namingFunction (): Namer { + public get namingFunction(): Namer { return defined(this._namingFunction); } // Must return at least one proposal. The proposals are considered in order. - abstract proposeUnstyledNames (names: ReadonlyMap): ReadonlySet; + public abstract proposeUnstyledNames(names: ReadonlyMap): ReadonlySet; - firstProposedName (names: ReadonlyMap): string { + public firstProposedName(names: ReadonlyMap): string { return defined(iterableFirst(this.proposeUnstyledNames(names))); } - nameAssignments (forbiddenNames: ReadonlySet, assignedName: string): ReadonlyMap | null { + public nameAssignments( + forbiddenNames: ReadonlySet, + assignedName: string + ): ReadonlyMap | null { if (forbiddenNames.has(assignedName)) return null; const assignments = new Map([[this, assignedName]]); for (const an of this._associates) { @@ -222,23 +232,23 @@ export abstract class Name { // FIXME: FixedNameds should optionally be user-configurable export class FixedName extends Name { - constructor (private readonly _fixedName: string) { + public constructor(private readonly _fixedName: string) { super(undefined, 0); } - get dependencies (): readonly Name[] { + public get dependencies(): readonly Name[] { return []; } - addAssociate (_: AssociatedName): never { + public addAssociate(_: AssociatedName): never { return panic("Cannot add associates to fixed names"); } - get fixedName (): string { + public get fixedName(): string { return this._fixedName; } - proposeUnstyledNames (_?: ReadonlyMap): ReadonlySet { + public proposeUnstyledNames(_?: ReadonlyMap): ReadonlySet { return panic("Only fixedName should be called on FixedName."); } } @@ -246,30 +256,34 @@ export class FixedName extends Name { export class SimpleName extends Name { private readonly _unstyledNames: ReadonlySet; - constructor (unstyledNames: Iterable, namingFunction: Namer, order: number) { + public constructor(unstyledNames: Iterable, namingFunction: Namer, order: number) { super(namingFunction, order); this._unstyledNames = new Set(unstyledNames); } - get dependencies (): readonly Name[] { + public get dependencies(): readonly Name[] { return []; } - proposeUnstyledNames (_?: ReadonlyMap): ReadonlySet { + public proposeUnstyledNames(_?: ReadonlyMap): ReadonlySet { return this._unstyledNames; } } export class AssociatedName extends Name { - constructor (private readonly _sponsor: Name, order: number, readonly getName: (sponsorName: string) => string) { + public constructor( + private readonly _sponsor: Name, + order: number, + public readonly getName: (sponsorName: string) => string + ) { super(undefined, order); } - get dependencies (): readonly Name[] { + public get dependencies(): readonly Name[] { return [this._sponsor]; } - proposeUnstyledNames (_?: ReadonlyMap): never { + public proposeUnstyledNames(_?: ReadonlyMap): never { return panic("AssociatedName must be assigned via its sponsor"); } } @@ -277,10 +291,10 @@ export class AssociatedName extends Name { export class DependencyName extends Name { private readonly _dependencies: ReadonlySet; - constructor ( + public constructor( namingFunction: Namer | undefined, order: number, - private readonly _proposeUnstyledName: (lookup: (n: Name) => string) => string, + private readonly _proposeUnstyledName: (lookup: (n: Name) => string) => string ) { super(namingFunction, order); const dependencies: Name[] = []; @@ -291,21 +305,21 @@ export class DependencyName extends Name { this._dependencies = new Set(dependencies); } - get dependencies (): readonly Name[] { + public get dependencies(): readonly Name[] { return Array.from(this._dependencies); } - proposeUnstyledNames (names: ReadonlyMap): ReadonlySet { + public proposeUnstyledNames(names: ReadonlyMap): ReadonlySet { return new Set([ this._proposeUnstyledName(n => { assert(this._dependencies.has(n), "DependencyName proposer is not pure"); return defined(names.get(n)); - }), + }) ]); } } -export function keywordNamespace (name: string, keywords: string[]) { +export function keywordNamespace(name: string, keywords: string[]) { const ns = new Namespace(name, undefined, [], []); for (const kw of keywords) { ns.add(new FixedName(kw)); @@ -314,7 +328,7 @@ export function keywordNamespace (name: string, keywords: string[]) { return ns; } -function allNamespacesRecursively (namespaces: Iterable): ReadonlySet { +function allNamespacesRecursively(namespaces: Iterable): ReadonlySet { return setUnion(namespaces, ...Array.from(setMap(namespaces, ns => allNamespacesRecursively(ns.children)))); } @@ -323,26 +337,26 @@ class NamingContext { private readonly _namedsForName: Map> = new Map(); - readonly namespaces: ReadonlySet; + public readonly namespaces: ReadonlySet; - constructor (rootNamespaces: Iterable) { + public constructor(rootNamespaces: Iterable) { this.namespaces = allNamespacesRecursively(rootNamespaces); } - get names (): ReadonlyMap { + public get names(): ReadonlyMap { return this._names; } - isReadyToBeNamed = (named: Name): boolean => { + public isReadyToBeNamed(named: Name): boolean { if (this._names.has(named)) return false; return named.dependencies.every((n: Name) => this._names.has(n)); - }; + } - areForbiddensFullyNamed (namespace: Namespace): boolean { + public areForbiddensFullyNamed(namespace: Namespace): boolean { return iterableEvery(namespace.forbiddenNameds, n => this._names.has(n)); } - isConflicting = (namedNamespace: Namespace, proposed: string): boolean => { + public isConflicting(namedNamespace: Namespace, proposed: string): boolean { const namedsForProposed = this._namedsForName.get(proposed); // If the name is not assigned at all, there is no conflict. if (namedsForProposed === undefined) return false; @@ -354,9 +368,9 @@ class NamingContext { } return false; - }; + } - assign = (named: Name, namedNamespace: Namespace, name: string): void => { + public assign(named: Name, namedNamespace: Namespace, name: string): void { assert(!this.names.has(named), `Name "${name}" assigned twice`); assert(!this.isConflicting(namedNamespace, name), `Assigned name "${name}" conflicts`); this._names.set(named, name); @@ -367,11 +381,11 @@ class NamingContext { } namedsForName.add(named); - }; + } } // Naming algorithm -export function assignNames (rootNamespaces: Iterable): ReadonlyMap { +export function assignNames(rootNamespaces: Iterable): ReadonlyMap { const ctx = new NamingContext(rootNamespaces); // Assign all fixed names. @@ -415,7 +429,7 @@ export function assignNames (rootNamespaces: Iterable): ReadonlyMap n.namingFunction); for (const [namer, namedsForNamingFunction] of byNamingFunction) { const byProposed = setGroupBy(namedsForNamingFunction, n => - n.namingFunction.nameStyle(n.firstProposedName(ctx.names)), + n.namingFunction.nameStyle(n.firstProposedName(ctx.names)) ); for (const [, nameds] of byProposed) { // 3. Use each set's naming function to name its members. diff --git a/packages/quicktype-core/src/Renderer.ts b/packages/quicktype-core/src/Renderer.ts index b0665f36f..f22dc7c0a 100644 --- a/packages/quicktype-core/src/Renderer.ts +++ b/packages/quicktype-core/src/Renderer.ts @@ -1,11 +1,11 @@ import { iterableEnumerate } from "collection-utils"; import { type TypeGraph } from "./TypeGraph"; -import { type Name, type Namespace} from "./Naming"; +import { type Name, type Namespace } from "./Naming"; import { assignNames } from "./Naming"; -import { type Source, type Sourcelike, type NewlineSource} from "./Source"; +import { type Source, type Sourcelike, type NewlineSource } from "./Source"; import { annotated, sourcelikeToSource, newline } from "./Source"; -import { type AnnotationData} from "./Annotation"; +import { type AnnotationData } from "./Annotation"; import { IssueAnnotationData } from "./Annotation"; import { assert, panic } from "./support/Support"; import { type TargetLanguage } from "./TargetLanguage"; @@ -19,7 +19,7 @@ export interface RenderResult { export type BlankLinePosition = "none" | "interposing" | "leading" | "leading-and-interposing"; export type BlankLineConfig = BlankLinePosition | [BlankLinePosition, number]; -function getBlankLineConfig (cfg: BlankLineConfig): { count: number, position: BlankLinePosition, } { +function getBlankLineConfig(cfg: BlankLineConfig): { count: number; position: BlankLinePosition } { if (Array.isArray(cfg)) { return { position: cfg[0], count: cfg[1] }; } @@ -27,7 +27,7 @@ function getBlankLineConfig (cfg: BlankLineConfig): { count: number, position: B return { position: cfg, count: 1 }; } -function lineIndentation (line: string): { indent: number, text: string | null, } { +function lineIndentation(line: string): { indent: number; text: string | null } { const len = line.length; let indent = 0; for (let i = 0; i < len; i++) { @@ -54,48 +54,44 @@ export type ForEachPosition = "first" | "last" | "middle" | "only"; class EmitContext { private _lastNewline?: NewlineSource; - // @ts-expect-error: Initialized in startEmit, which is called from the constructor private readonly _emitted: Sourcelike[]; - // @ts-expect-error: Initialized in startEmit, which is called from the constructor private readonly _currentEmitTarget: Sourcelike[]; - // @ts-expect-error: Initialized in startEmit, which is called from the constructor private _numBlankLinesNeeded: number; - // @ts-expect-error: Initialized in startEmit, which is called from the constructor private _preventBlankLine: boolean; - constructor () { + public constructor() { this._currentEmitTarget = this._emitted = []; this._numBlankLinesNeeded = 0; this._preventBlankLine = true; // no blank lines at start of file } - get isEmpty (): boolean { + public get isEmpty(): boolean { return this._emitted.length === 0; } - get isNested (): boolean { + public get isNested(): boolean { return this._emitted !== this._currentEmitTarget; } - get source (): Sourcelike[] { + public get source(): Sourcelike[] { return this._emitted; } - private pushItem (item: Sourcelike): void { + public pushItem(item: Sourcelike): void { this._currentEmitTarget.push(item); this._preventBlankLine = false; } - emitNewline (): void { + public emitNewline(): void { const nl = newline(); this.pushItem(nl); this._lastNewline = nl; } - emitItem (item: Sourcelike): void { + public emitItem(item: Sourcelike): void { if (!this.isEmpty) { for (let i = 0; i < this._numBlankLinesNeeded; i++) { this.emitNewline(); @@ -106,22 +102,22 @@ class EmitContext { this.pushItem(item); } - containsItem (item: Sourcelike): boolean { + public containsItem(item: Sourcelike): boolean { const existingItem = this._currentEmitTarget.find((value: Sourcelike) => item === value); return existingItem !== undefined; } - ensureBlankLine (numBlankLines: number): void { + public ensureBlankLine(numBlankLines: number): void { if (this._preventBlankLine) return; this._numBlankLinesNeeded = Math.max(this._numBlankLinesNeeded, numBlankLines); } - preventBlankLine (): void { + public preventBlankLine(): void { this._numBlankLinesNeeded = 0; this._preventBlankLine = true; } - changeIndent (offset: number): void { + public changeIndent(offset: number): void { if (this._lastNewline === undefined) { return panic("Cannot change indent for the first line"); } @@ -143,9 +139,9 @@ export abstract class Renderer { private _emitContext: EmitContext; - constructor ( + public constructor( protected readonly targetLanguage: TargetLanguage, - renderContext: RenderContext, + renderContext: RenderContext ) { this.typeGraph = renderContext.typeGraph; this.leadingComments = renderContext.leadingComments; @@ -155,19 +151,20 @@ export abstract class Renderer { this._emitContext = new EmitContext(); } - ensureBlankLine (numBlankLines = 1): void { + // FIXME: make protected once JavaDateTimeRenderer is refactored + public ensureBlankLine(numBlankLines = 1): void { this._emitContext.ensureBlankLine(numBlankLines); } - preventBlankLine (): void { + protected preventBlankLine(): void { this._emitContext.preventBlankLine(); } - emitItem (item: Sourcelike): void { + protected emitItem(item: Sourcelike): void { this._emitContext.emitItem(item); } - emitItemOnce (item: Sourcelike): boolean { + protected emitItemOnce(item: Sourcelike): boolean { if (this._emitContext.containsItem(item)) { return false; } @@ -176,7 +173,7 @@ export abstract class Renderer { return true; } - emitLineOnce (...lineParts: Sourcelike[]): void { + protected emitLineOnce(...lineParts: Sourcelike[]): void { let lineEmitted = true; if (lineParts.length === 1) { lineEmitted = this.emitItemOnce(lineParts[0]); @@ -189,7 +186,8 @@ export abstract class Renderer { } } - emitLine (...lineParts: Sourcelike[]): void { + // FIXME: make protected once JavaDateTimeRenderer is refactored + public emitLine(...lineParts: Sourcelike[]): void { if (lineParts.length === 1) { this._emitContext.emitItem(lineParts[0]); } else if (lineParts.length > 1) { @@ -199,7 +197,7 @@ export abstract class Renderer { this._emitContext.emitNewline(); } - emitMultiline (linesString: string): void { + protected emitMultiline(linesString: string): void { const lines = linesString.split("\n"); const numLines = lines.length; if (numLines === 0) return; @@ -224,7 +222,7 @@ export abstract class Renderer { } } - gatherSource (emitter: () => void): Sourcelike[] { + protected gatherSource(emitter: () => void): Sourcelike[] { const oldEmitContext = this._emitContext; this._emitContext = new EmitContext(); emitter(); @@ -234,19 +232,19 @@ export abstract class Renderer { return source; } - emitGatheredSource (items: Sourcelike[]): void { + protected emitGatheredSource(items: Sourcelike[]): void { for (const item of items) { this._emitContext.emitItem(item); } } - emitAnnotated (annotation: AnnotationData, emitter: () => void): void { + protected emitAnnotated(annotation: AnnotationData, emitter: () => void): void { const lines = this.gatherSource(emitter); const source = sourcelikeToSource(lines); this._emitContext.emitItem(annotated(annotation, source)); } - emitIssue (message: string, emitter: () => void): void { + protected emitIssue(message: string, emitter: () => void): void { this.emitAnnotated(new IssueAnnotationData(message), emitter); } @@ -257,11 +255,11 @@ export abstract class Renderer { this._emitContext.emitNewline(); }; - changeIndent (offset: number): void { + protected changeIndent(offset: number): void { this._emitContext.changeIndent(offset); } - iterableForEach(iterable: Iterable, emitter: (v: T, position: ForEachPosition) => void): void { + protected iterableForEach(iterable: Iterable, emitter: (v: T, position: ForEachPosition) => void): void { const items = Array.from(iterable); let onFirst = true; for (const [i, v] of iterableEnumerate(items)) { @@ -272,11 +270,11 @@ export abstract class Renderer { } } - forEach( + protected forEach( iterable: Iterable<[K, V]>, interposedBlankLines: number, leadingBlankLines: number, - emitter: (v: V, k: K, position: ForEachPosition) => void, + emitter: (v: V, k: K, position: ForEachPosition) => void ): boolean { let didEmit = false; this.iterableForEach(iterable, ([k, v], position) => { @@ -292,10 +290,10 @@ export abstract class Renderer { return didEmit; } - forEachWithBlankLines( + protected forEachWithBlankLines( iterable: Iterable<[K, V]>, blankLineConfig: BlankLineConfig, - emitter: (v: V, k: K, position: ForEachPosition) => void, + emitter: (v: V, k: K, position: ForEachPosition) => void ): boolean { const { position, count } = getBlankLineConfig(blankLineConfig); const interposing = ["interposing", "leading-and-interposing"].includes(position); @@ -303,20 +301,21 @@ export abstract class Renderer { return this.forEach(iterable, interposing ? count : 0, leading ? count : 0, emitter); } - indent (fn: () => void): void { + // FIXME: make protected once JavaDateTimeRenderer is refactored + public indent(fn: () => void): void { this.changeIndent(1); fn(); this.changeIndent(-1); } - protected abstract setUpNaming (): Iterable; - protected abstract emitSource (givenOutputFilename: string): void; + protected abstract setUpNaming(): Iterable; + protected abstract emitSource(givenOutputFilename: string): void; - private assignNames (): ReadonlyMap { + protected assignNames(): ReadonlyMap { return assignNames(this.setUpNaming()); } - protected initializeEmitContextForFilename (filename: string): void { + protected initializeEmitContextForFilename(filename: string): void { if (this._finishedEmitContexts.has(filename.toLowerCase())) { const existingEmitContext = this._finishedEmitContexts.get(filename.toLowerCase()); if (existingEmitContext !== undefined) { @@ -325,10 +324,10 @@ export abstract class Renderer { } } - protected finishFile (filename: string): void { + protected finishFile(filename: string): void { if (this._finishedFiles.has(filename)) { console.log( - `[WARNING] Tried to emit file ${filename} more than once. If performing multi-file output this warning can be safely ignored.`, + `[WARNING] Tried to emit file ${filename} more than once. If performing multi-file output this warning can be safely ignored.` ); } @@ -340,7 +339,7 @@ export abstract class Renderer { this._emitContext = new EmitContext(); } - render (givenOutputFilename: string): RenderResult { + public render(givenOutputFilename: string): RenderResult { this._names = this.assignNames(); this.emitSource(givenOutputFilename); if (!this._emitContext.isEmpty) { @@ -350,7 +349,7 @@ export abstract class Renderer { return { sources: this._finishedFiles, names: this._names }; } - get names (): ReadonlyMap { + public get names(): ReadonlyMap { if (this._names === undefined) { return panic("Names accessed before they were assigned"); } diff --git a/packages/quicktype-core/src/RendererOptions.ts b/packages/quicktype-core/src/RendererOptions.ts index f3fae9ffa..4aab7d4ec 100644 --- a/packages/quicktype-core/src/RendererOptions.ts +++ b/packages/quicktype-core/src/RendererOptions.ts @@ -27,15 +27,15 @@ export interface OptionDefinition { * subclasses, `BooleanOption`, `EnumOption`, or `StringOption`. */ export abstract class Option { - readonly definition: OptionDefinition; + public readonly definition: OptionDefinition; - constructor (definition: OptionDefinition) { + public constructor(definition: OptionDefinition) { definition.renderer = true; this.definition = definition; assert(definition.kind !== undefined, "Renderer option kind must be defined"); } - getValue (values: { [name: string]: any, }): T { + public getValue(values: { [name: string]: any }): T { const value = values[this.definition.name]; if (value === undefined) { return this.definition.defaultValue; @@ -44,7 +44,7 @@ export abstract class Option { return value; } - get cliDefinitions (): { actual: OptionDefinition[], display: OptionDefinition[], } { + public get cliDefinitions(): { actual: OptionDefinition[]; display: OptionDefinition[] } { return { actual: [this.definition], display: [this.definition] }; } } @@ -52,11 +52,11 @@ export abstract class Option { export type OptionValueType = O extends Option ? T : never; export type OptionValues = { [P in keyof T]: OptionValueType }; -export function getOptionValues, }> ( +export function getOptionValues }>( options: T, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): OptionValues { - const optionValues: { [name: string]: any, } = {}; + const optionValues: { [name: string]: any } = {}; for (const name of Object.getOwnPropertyNames(options)) { optionValues[name] = options[name].getValue(untypedOptionValues); } @@ -74,32 +74,32 @@ export class BooleanOption extends Option { * @param defaultValue The default value. * @param kind Whether it's a primary or secondary option. */ - constructor (name: string, description: string, defaultValue: boolean, kind: OptionKind = "primary") { + public constructor(name: string, description: string, defaultValue: boolean, kind: OptionKind = "primary") { super({ name, kind, type: Boolean, description, - defaultValue, + defaultValue }); } - get cliDefinitions (): { actual: OptionDefinition[], display: OptionDefinition[], } { + public get cliDefinitions(): { actual: OptionDefinition[]; display: OptionDefinition[] } { const negated = Object.assign({}, this.definition, { name: `no-${this.definition.name}`, - defaultValue: !this.definition.defaultValue, + defaultValue: !this.definition.defaultValue }); const display = Object.assign({}, this.definition, { name: `[no-]${this.definition.name}`, - description: `${this.definition.description} (${this.definition.defaultValue ? "on" : "off"} by default)`, + description: `${this.definition.description} (${this.definition.defaultValue ? "on" : "off"} by default)` }); return { display: [display], - actual: [this.definition, negated], + actual: [this.definition, negated] }; } - getValue (values: { [name: string]: any, }): boolean { + public getValue(values: { [name: string]: any }): boolean { let value = values[this.definition.name]; if (value === undefined) { value = this.definition.defaultValue; @@ -125,12 +125,12 @@ export class BooleanOption extends Option { } export class StringOption extends Option { - constructor ( + public constructor( name: string, description: string, typeLabel: string, defaultValue: string, - kind: OptionKind = "primary", + kind: OptionKind = "primary" ) { const definition = { name, @@ -138,21 +138,21 @@ export class StringOption extends Option { type: String, description, typeLabel, - defaultValue, + defaultValue }; super(definition); } } export class EnumOption extends Option { - private readonly _values: { [name: string]: T, }; + private readonly _values: { [name: string]: T }; - constructor ( + public constructor( name: string, description: string, values: Array<[string, T]>, defaultValue: string | undefined = undefined, - kind: OptionKind = "primary", + kind: OptionKind = "primary" ) { if (defaultValue === undefined) { defaultValue = values[0][0]; @@ -165,7 +165,7 @@ export class EnumOption extends Option { description, typeLabel: values.map(([n, _]) => n).join("|"), legalValues: values.map(([n, _]) => n), - defaultValue, + defaultValue }; super(definition); @@ -175,7 +175,7 @@ export class EnumOption extends Option { } } - getValue (values: { [name: string]: any, }): T { + public getValue(values: { [name: string]: any }): T { let name: string = values[this.definition.name]; if (name === undefined) { name = this.definition.defaultValue; diff --git a/packages/quicktype-core/src/Run.ts b/packages/quicktype-core/src/Run.ts index 1faaed8e6..2e2790781 100644 --- a/packages/quicktype-core/src/Run.ts +++ b/packages/quicktype-core/src/Run.ts @@ -8,7 +8,7 @@ import { combineClasses } from "./rewrites/CombineClasses"; import { inferMaps } from "./rewrites/InferMaps"; import { type StringTypeMapping } from "./TypeBuilder"; import { TypeBuilder } from "./TypeBuilder"; -import { type TypeGraph} from "./TypeGraph"; +import { type TypeGraph } from "./TypeGraph"; import { noneToAny, optionalToNullable, removeIndirectionIntersections } from "./TypeGraph"; import { initTypeNames } from "./attributes/TypeNames"; import { gatherNames } from "./GatherNames"; @@ -23,7 +23,7 @@ import { makeTransformations } from "./MakeTransformations"; import { type TransformedStringTypeKind } from "./Type"; import { type Comment } from "./support/Comments"; -export function getTargetLanguage (nameOrInstance: string | TargetLanguage): TargetLanguage { +export function getTargetLanguage(nameOrInstance: string | TargetLanguage): TargetLanguage { if (typeof nameOrInstance === "object") { return nameOrInstance; } @@ -37,7 +37,7 @@ export function getTargetLanguage (nameOrInstance: string | TargetLanguage): Tar } export interface RendererOptions { - [name: string]: string | boolean; + [name: string]: string | boolean; } export interface InferenceFlag { @@ -54,14 +54,14 @@ export const inferenceFlagsObject = { description: "Detect maps", negationDescription: "Don't infer maps, always use classes", explanation: "Infer maps when object keys look like map keys.", - order: 1, + order: 1 }, /** Whether to infer enum types from JSON data */ inferEnums: { description: "Detect enums", negationDescription: "Don't infer enums, always use strings", explanation: "If string values occur within a relatively small domain,\ninfer them as enum values.", - order: 2, + order: 2 }, /** Whether to convert UUID strings to UUID objects */ inferUuids: { @@ -69,7 +69,7 @@ export const inferenceFlagsObject = { negationDescription: "Don't convert UUIDs to UUID objects", explanation: "Detect UUIDs like '123e4567-e89b-12d3-a456-426655440000' (partial support).", stringType: "uuid" as TransformedStringTypeKind, - order: 3, + order: 3 }, /** Whether to assume that JSON strings that look like dates are dates */ inferDateTimes: { @@ -77,24 +77,24 @@ export const inferenceFlagsObject = { negationDescription: "Don't infer dates or times", explanation: "Infer dates from strings (partial support).", stringType: "date-time" as TransformedStringTypeKind, - order: 4, + order: 4 }, /** Whether to convert stringified integers to integers */ inferIntegerStrings: { description: "Detect integers in strings", negationDescription: "Don't convert stringified integers to integers", - explanation: "Automatically convert stringified integers to integers.\nFor example, \"1\" is converted to 1.", + explanation: 'Automatically convert stringified integers to integers.\nFor example, "1" is converted to 1.', stringType: "integer-string" as TransformedStringTypeKind, - order: 5, + order: 5 }, /** Whether to convert stringified booleans to boolean values */ inferBooleanStrings: { description: "Detect booleans in strings", negationDescription: "Don't convert stringified booleans to booleans", explanation: - "Automatically convert stringified booleans to booleans.\nFor example, \"true\" is converted to true.", + 'Automatically convert stringified booleans to booleans.\nFor example, "true" is converted to true.', stringType: "bool-string" as TransformedStringTypeKind, - order: 6, + order: 6 }, /** Combine similar classes. This doesn't apply to classes from a schema, only from inference. */ combineClasses: { @@ -102,7 +102,7 @@ export const inferenceFlagsObject = { negationDescription: "Don't combine similar classes", explanation: "Combine classes with significantly overlapping properties,\ntreating contingent properties as nullable.", - order: 7, + order: 7 }, /** Whether to treat $ref as references within JSON */ ignoreJsonRefs: { @@ -110,8 +110,8 @@ export const inferenceFlagsObject = { negationDescription: "Treat $ref as a reference in JSON", explanation: "Like in JSON Schema, allow objects like\n'{ $ref: \"#/foo/bar\" }' to refer\nto another part of the input.", - order: 8, - }, + order: 8 + } }; export type InferenceFlagName = keyof typeof inferenceFlagsObject; export const inferenceFlagNames = Object.getOwnPropertyNames(inferenceFlagsObject) as InferenceFlagName[]; @@ -194,7 +194,7 @@ const defaultOptions: NonInferenceOptions = { debugPrintGatherNames: false, debugPrintTransformations: false, debugPrintTimes: false, - debugPrintSchemaResolving: false, + debugPrintSchemaResolving: false }; export interface RunContext { @@ -214,7 +214,7 @@ interface GraphInputs { typeBuilder: TypeBuilder; } -function makeDefaultInferenceFlags (): InferenceFlags { +function makeDefaultInferenceFlags(): InferenceFlags { const flags = {} as InferenceFlags; for (const flag of inferenceFlagNames) { flags[flag] = true; @@ -228,7 +228,7 @@ export const defaultInferenceFlags = makeDefaultInferenceFlags(); class Run implements RunContext { private readonly _options: Options; - constructor (options: Partial) { + public constructor(options: Partial) { // We must not overwrite defaults with undefined values, which // we sometimes get. this._options = Object.assign({}, defaultOptions, defaultInferenceFlags); @@ -240,7 +240,7 @@ class Run implements RunContext { } } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const targetLanguage = getTargetLanguage(this._options.lang); const mapping = new Map(targetLanguage.stringTypeMapping); for (const flag of inferenceFlagNames) { @@ -253,19 +253,19 @@ class Run implements RunContext { return mapping; } - get debugPrintReconstitution (): boolean { + public get debugPrintReconstitution(): boolean { return this._options.debugPrintReconstitution === true; } - get debugPrintTransformations (): boolean { + public get debugPrintTransformations(): boolean { return this._options.debugPrintTransformations; } - get debugPrintSchemaResolving (): boolean { + public get debugPrintSchemaResolving(): boolean { return this._options.debugPrintSchemaResolving; } - async timeSync(name: string, f: () => Promise): Promise { + public async timeSync(name: string, f: () => Promise): Promise { const start = Date.now(); const result = await f(); const end = Date.now(); @@ -276,7 +276,7 @@ class Run implements RunContext { return result; } - time(name: string, f: () => T): T { + public time(name: string, f: () => T): T { const start = Date.now(); const result = f(); const end = Date.now(); @@ -287,7 +287,7 @@ class Run implements RunContext { return result; } - private makeGraphInputs (): GraphInputs { + private makeGraphInputs(): GraphInputs { const targetLanguage = getTargetLanguage(this._options.lang); const stringTypeMapping = this.stringTypeMapping; const conflateNumbers = !targetLanguage.supportsUnionsWithBothNumberTypes; @@ -297,13 +297,13 @@ class Run implements RunContext { this._options.alphabetizeProperties, this._options.allPropertiesOptional, this._options.checkProvenance, - false, + false ); return { targetLanguage, stringTypeMapping, conflateNumbers, typeBuilder }; } - private async makeGraph (allInputs: InputData): Promise { + private async makeGraph(allInputs: InputData): Promise { const graphInputs = this.makeGraphInputs(); await this.timeSync( @@ -314,14 +314,14 @@ class Run implements RunContext { graphInputs.typeBuilder, this._options.inferMaps, this._options.inferEnums, - this._options.fixedTopLevels, - ), + this._options.fixedTopLevels + ) ); return this.processGraph(allInputs, graphInputs); } - private makeGraphSync (allInputs: InputData): TypeGraph { + private makeGraphSync(allInputs: InputData): TypeGraph { const graphInputs = this.makeGraphInputs(); this.time("read input", () => @@ -330,14 +330,14 @@ class Run implements RunContext { graphInputs.typeBuilder, this._options.inferMaps, this._options.inferEnums, - this._options.fixedTopLevels, - ), + this._options.fixedTopLevels + ) ); return this.processGraph(allInputs, graphInputs); } - private processGraph (allInputs: InputData, graphInputs: GraphInputs): TypeGraph { + private processGraph(allInputs: InputData, graphInputs: GraphInputs): TypeGraph { const { targetLanguage, stringTypeMapping, conflateNumbers, typeBuilder } = graphInputs; let graph = typeBuilder.finish(); @@ -351,7 +351,7 @@ class Run implements RunContext { if (typeBuilder.didAddForwardingIntersection || !this._options.ignoreJsonRefs) { this.time( "remove indirection intersections", - () => graph = removeIndirectionIntersections(graph, stringTypeMapping, debugPrintReconstitution), + () => (graph = removeIndirectionIntersections(graph, stringTypeMapping, debugPrintReconstitution)) ); } @@ -364,11 +364,11 @@ class Run implements RunContext { this.time( "resolve intersections", () => - [graph, intersectionsDone] = resolveIntersections( + ([graph, intersectionsDone] = resolveIntersections( graph, stringTypeMapping, - debugPrintReconstitution, - ), + debugPrintReconstitution + )) ); } @@ -376,13 +376,13 @@ class Run implements RunContext { this.time( "flatten unions", () => - [graph, unionsDone] = flattenUnions( + ([graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, true, - debugPrintReconstitution, - ), + debugPrintReconstitution + )) ); } @@ -395,31 +395,31 @@ class Run implements RunContext { this.time( "replace object type", () => - graph = replaceObjectType( + (graph = replaceObjectType( graph, stringTypeMapping, conflateNumbers, targetLanguage.supportsFullObjectType, - debugPrintReconstitution, - ), + debugPrintReconstitution + )) ); do { this.time( "flatten unions", () => - [graph, unionsDone] = flattenUnions( + ([graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, false, - debugPrintReconstitution, - ), + debugPrintReconstitution + )) ); } while (!unionsDone); if (this._options.combineClasses) { const combinedGraph = this.time("combine classes", () => - combineClasses(this, graph, this._options.alphabetizeProperties, true, false, debugPrintReconstitution), + combineClasses(this, graph, this._options.alphabetizeProperties, true, false, debugPrintReconstitution) ); if (combinedGraph === graph) { graph = combinedGraph; @@ -427,14 +427,14 @@ class Run implements RunContext { this.time( "combine classes cleanup", () => - graph = combineClasses( + (graph = combineClasses( this, combinedGraph, this._options.alphabetizeProperties, false, true, - debugPrintReconstitution, - ), + debugPrintReconstitution + )) ); } } @@ -442,7 +442,7 @@ class Run implements RunContext { if (this._options.inferMaps) { for (;;) { const newGraph = this.time("infer maps", () => - inferMaps(graph, stringTypeMapping, true, debugPrintReconstitution), + inferMaps(graph, stringTypeMapping, true, debugPrintReconstitution) ); if (newGraph === graph) { break; @@ -453,49 +453,49 @@ class Run implements RunContext { } const enumInference = allInputs.needSchemaProcessing ? "all" : this._options.inferEnums ? "infer" : "none"; - this.time("expand strings", () => graph = expandStrings(this, graph, enumInference)); + this.time("expand strings", () => (graph = expandStrings(this, graph, enumInference))); this.time( "flatten unions", () => - [graph, unionsDone] = flattenUnions( + ([graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, false, - debugPrintReconstitution, - ), + debugPrintReconstitution + )) ); assert(unionsDone, "We should only have to flatten unions once after expanding strings"); if (allInputs.needSchemaProcessing) { this.time( "flatten strings", - () => graph = flattenStrings(graph, stringTypeMapping, debugPrintReconstitution), + () => (graph = flattenStrings(graph, stringTypeMapping, debugPrintReconstitution)) ); } - this.time("none to any", () => graph = noneToAny(graph, stringTypeMapping, debugPrintReconstitution)); + this.time("none to any", () => (graph = noneToAny(graph, stringTypeMapping, debugPrintReconstitution))); if (!targetLanguage.supportsOptionalClassProperties) { this.time( "optional to nullable", - () => graph = optionalToNullable(graph, stringTypeMapping, debugPrintReconstitution), + () => (graph = optionalToNullable(graph, stringTypeMapping, debugPrintReconstitution)) ); } - this.time("fixed point", () => graph = graph.rewriteFixedPoint(false, debugPrintReconstitution)); + this.time("fixed point", () => (graph = graph.rewriteFixedPoint(false, debugPrintReconstitution))); - this.time("make transformations", () => graph = makeTransformations(this, graph, targetLanguage)); + this.time("make transformations", () => (graph = makeTransformations(this, graph, targetLanguage))); this.time( "flatten unions", () => - [graph, unionsDone] = flattenUnions( + ([graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, false, - debugPrintReconstitution, - ), + debugPrintReconstitution + )) ); assert(unionsDone, "We should only have to flatten unions once after making transformations"); @@ -508,7 +508,7 @@ class Run implements RunContext { // is different from the one we started out with. this.time( "GC", - () => graph = graph.garbageCollect(this._options.alphabetizeProperties, debugPrintReconstitution), + () => (graph = graph.garbageCollect(this._options.alphabetizeProperties, debugPrintReconstitution)) ); if (this._options.debugPrintGraph) { @@ -516,7 +516,7 @@ class Run implements RunContext { } this.time("gather names", () => - gatherNames(graph, !allInputs.needSchemaProcessing, this._options.debugPrintGatherNames), + gatherNames(graph, !allInputs.needSchemaProcessing, this._options.debugPrintGatherNames) ); if (this._options.debugPrintGraph) { graph.printGraph(); @@ -525,14 +525,13 @@ class Run implements RunContext { return graph; } - private makeSimpleTextResult (lines: string[]): MultiFileRenderResult { - return new Map([[this._options.outputFilename, { lines, annotations: [] }]] as Array<[ - string, - SerializedRenderResult - ]>); + private makeSimpleTextResult(lines: string[]): MultiFileRenderResult { + return new Map([[this._options.outputFilename, { lines, annotations: [] }]] as Array< + [string, SerializedRenderResult] + >); } - private preRun (): MultiFileRenderResult | [InputData, TargetLanguage] { + private preRun(): MultiFileRenderResult | [InputData, TargetLanguage] { // FIXME: This makes quicktype not quite reentrant initTypeNames(); @@ -551,7 +550,7 @@ class Run implements RunContext { return [inputData, targetLanguage]; } - async run (): Promise { + public async run(): Promise { const preRunResult = this.preRun(); if (!Array.isArray(preRunResult)) { return preRunResult; @@ -564,7 +563,7 @@ class Run implements RunContext { return this.renderGraph(targetLanguage, graph); } - runSync (): MultiFileRenderResult { + public runSync(): MultiFileRenderResult { const preRunResult = this.preRun(); if (!Array.isArray(preRunResult)) { return preRunResult; @@ -577,7 +576,7 @@ class Run implements RunContext { return this.renderGraph(targetLanguage, graph); } - private renderGraph (targetLanguage: TargetLanguage, graph: TypeGraph): MultiFileRenderResult { + private renderGraph(targetLanguage: TargetLanguage, graph: TypeGraph): MultiFileRenderResult { if (this._options.noRender) { return this.makeSimpleTextResult(["Done.", ""]); } @@ -588,7 +587,7 @@ class Run implements RunContext { this._options.alphabetizeProperties, this._options.leadingComments, this._options.rendererOptions, - this._options.indentation, + this._options.indentation ); } } @@ -599,19 +598,19 @@ class Run implements RunContext { * @param options Partial options. For options that are not defined, the * defaults will be used. */ -export async function quicktypeMultiFile (options: Partial): Promise { +export async function quicktypeMultiFile(options: Partial): Promise { return await new Run(options).run(); } -export function quicktypeMultiFileSync (options: Partial): MultiFileRenderResult { +export function quicktypeMultiFileSync(options: Partial): MultiFileRenderResult { return new Run(options).runSync(); } -function offsetLocation (loc: Location, lineOffset: number): Location { +function offsetLocation(loc: Location, lineOffset: number): Location { return { line: loc.line + lineOffset, column: loc.column }; } -function offsetSpan (span: Span, lineOffset: number): Span { +function offsetSpan(span: Span, lineOffset: number): Span { return { start: offsetLocation(span.start, lineOffset), end: offsetLocation(span.end, lineOffset) }; } @@ -620,7 +619,7 @@ function offsetSpan (span: Span, lineOffset: number): Span { * are concatenated and prefixed with a `//`-style comment giving the * filename. */ -export function combineRenderResults (result: MultiFileRenderResult): SerializedRenderResult { +export function combineRenderResults(result: MultiFileRenderResult): SerializedRenderResult { if (result.size <= 1) { const first = mapFirst(result); if (first === undefined) { @@ -636,7 +635,7 @@ export function combineRenderResults (result: MultiFileRenderResult): Serialized const offset = lines.length + 2; lines = lines.concat([`// ${filename}`, ""], srr.lines); annotations = annotations.concat( - srr.annotations.map(ann => ({ annotation: ann.annotation, span: offsetSpan(ann.span, offset) })), + srr.annotations.map(ann => ({ annotation: ann.annotation, span: offsetSpan(ann.span, offset) })) ); } @@ -651,7 +650,7 @@ export function combineRenderResults (result: MultiFileRenderResult): Serialized * @param options Partial options. For options that are not defined, the * defaults will be used. */ -export async function quicktype (options: Partial): Promise { +export async function quicktype(options: Partial): Promise { const result = await quicktypeMultiFile(options); return combineRenderResults(result); } diff --git a/packages/quicktype-core/src/Source.ts b/packages/quicktype-core/src/Source.ts index 235ac9264..f47360c37 100644 --- a/packages/quicktype-core/src/Source.ts +++ b/packages/quicktype-core/src/Source.ts @@ -21,10 +21,10 @@ export interface TextSource { export interface NewlineSource { // Number of indentation levels (not spaces!) to change -// the rest of the source by. Positive numbers mean -// indent more, negative mean indent less. The most -// common value will be zero, for no change in -// indentation. + // the rest of the source by. Positive numbers mean + // indent more, negative mean indent less. The most + // common value will be zero, for no change in + // indentation. indentationChange: number; kind: "newline"; } @@ -56,7 +56,7 @@ export interface ModifiedSource { source: Source; } -export function newline (): NewlineSource { +export function newline(): NewlineSource { // We're returning a new object instead of using a singleton // here because `Renderer` will modify `indentationChange`. return { kind: "newline", indentationChange: 0 }; @@ -65,11 +65,11 @@ export function newline (): NewlineSource { export type Sourcelike = Source | string | Name | SourcelikeArray; export type SourcelikeArray = Sourcelike[]; -export function sourcelikeToSource (sl: Sourcelike): Source { +export function sourcelikeToSource(sl: Sourcelike): Source { if (sl instanceof Array) { return { kind: "sequence", - sequence: sl.map(sourcelikeToSource), + sequence: sl.map(sourcelikeToSource) }; } @@ -83,8 +83,8 @@ export function sourcelikeToSource (sl: Sourcelike): Source { kind: "sequence", sequence: arrayIntercalate( newline(), - lines.map((l: string) => ({ kind: "text", text: l } as Source)), - ), + lines.map((l: string) => ({ kind: "text", text: l }) as Source) + ) }; } @@ -95,15 +95,15 @@ export function sourcelikeToSource (sl: Sourcelike): Source { return sl; } -export function annotated (annotation: AnnotationData, sl: Sourcelike): Source { +export function annotated(annotation: AnnotationData, sl: Sourcelike): Source { return { kind: "annotated", annotation, - source: sourcelikeToSource(sl), + source: sourcelikeToSource(sl) }; } -export function maybeAnnotated (doAnnotate: boolean, annotation: AnnotationData, sl: Sourcelike): Sourcelike { +export function maybeAnnotated(doAnnotate: boolean, annotation: AnnotationData, sl: Sourcelike): Sourcelike { if (!doAnnotate) { return sl; } @@ -111,11 +111,11 @@ export function maybeAnnotated (doAnnotate: boolean, annotation: AnnotationData, return annotated(annotation, sl); } -export function modifySource (modifier: (serialized: string) => string, sl: Sourcelike): Sourcelike { +export function modifySource(modifier: (serialized: string) => string, sl: Sourcelike): Sourcelike { return { kind: "modified", modifier, - source: sourcelikeToSource(sl), + source: sourcelikeToSource(sl) }; } @@ -140,7 +140,7 @@ export interface SerializedRenderResult { lines: string[]; } -function sourceLineLength (source: Source, names: ReadonlyMap): number { +function sourceLineLength(source: Source, names: ReadonlyMap): number { switch (source.kind) { case "text": return source.text.length; @@ -163,10 +163,10 @@ function sourceLineLength (source: Source, names: ReadonlyMap): nu } } -export function serializeRenderResult ( +export function serializeRenderResult( rootSource: Source, names: ReadonlyMap, - indentation: string, + indentation: string ): SerializedRenderResult { let indent = 0; let indentNeeded = 0; @@ -175,28 +175,28 @@ export function serializeRenderResult ( let currentLine: string[] = []; const annotations: Annotation[] = []; - function indentIfNeeded (): void { + function indentIfNeeded(): void { if (indentNeeded === 0) return; currentLine.push(repeatString(indentation, indentNeeded)); indentNeeded = 0; } - function flattenCurrentLine (): string { + function flattenCurrentLine(): string { const str = currentLine.join(""); currentLine = [str]; return str; } - function currentLocation (): Location { + function currentLocation(): Location { return { line: lines.length, column: flattenCurrentLine().length }; } - function finishLine (): void { + function finishLine(): void { lines.push(flattenCurrentLine()); currentLine = []; } - function serializeToStringArray (source: Source): void { + function serializeToStringArray(source: Source): void { switch (source.kind) { case "text": indentIfNeeded(); @@ -278,11 +278,11 @@ export interface MultiWord { source: Sourcelike; } -export function singleWord (...source: Sourcelike[]): MultiWord { +export function singleWord(...source: Sourcelike[]): MultiWord { return { source, needsParens: false }; } -export function multiWord (separator: Sourcelike, ...words: Sourcelike[]): MultiWord { +export function multiWord(separator: Sourcelike, ...words: Sourcelike[]): MultiWord { assert(words.length > 0, "Zero words is not multiple"); if (words.length === 1) { return singleWord(words[0]); @@ -297,7 +297,7 @@ export function multiWord (separator: Sourcelike, ...words: Sourcelike[]): Multi return { source: items, needsParens: true }; } -export function parenIfNeeded ({ source, needsParens }: MultiWord): Sourcelike { +export function parenIfNeeded({ source, needsParens }: MultiWord): Sourcelike { if (needsParens) { return ["(", source, ")"]; } diff --git a/packages/quicktype-core/src/TargetLanguage.ts b/packages/quicktype-core/src/TargetLanguage.ts index 4d9dbce50..7f41b919e 100644 --- a/packages/quicktype-core/src/TargetLanguage.ts +++ b/packages/quicktype-core/src/TargetLanguage.ts @@ -9,26 +9,26 @@ import { type StringTypeMapping } from "./TypeBuilder"; import { defined } from "./support/Support"; import { type ConvenienceRenderer } from "./ConvenienceRenderer"; import { type Type } from "./Type"; -import { type DateTimeRecognizer} from "./DateTime"; +import { type DateTimeRecognizer } from "./DateTime"; import { DefaultDateTimeRecognizer } from "./DateTime"; import { type Comment } from "./support/Comments"; export type MultiFileRenderResult = ReadonlyMap; export abstract class TargetLanguage { - constructor ( - readonly displayName: string, - readonly names: string[], - readonly extension: string, + public constructor( + public readonly displayName: string, + public readonly names: string[], + public readonly extension: string ) {} - protected abstract getOptions (): Array>; + protected abstract getOptions(): Array>; - get optionDefinitions (): OptionDefinition[] { + public get optionDefinitions(): OptionDefinition[] { return this.getOptions().map(o => o.definition); } - get cliOptionDefinitions (): { actual: OptionDefinition[], display: OptionDefinition[], } { + public get cliOptionDefinitions(): { actual: OptionDefinition[]; display: OptionDefinition[] } { let actual: OptionDefinition[] = []; let display: OptionDefinition[] = []; for (const { cliDefinitions } of this.getOptions()) { @@ -39,19 +39,19 @@ export abstract class TargetLanguage { return { actual, display }; } - get name (): string { + public get name(): string { return defined(this.names[0]); } - protected abstract makeRenderer (renderContext: RenderContext, optionValues: { [name: string]: any, }): Renderer; + protected abstract makeRenderer(renderContext: RenderContext, optionValues: { [name: string]: any }): Renderer; - renderGraphAndSerialize ( + public renderGraphAndSerialize( typeGraph: TypeGraph, givenOutputFilename: string, alphabetizeProperties: boolean, leadingComments: Comment[] | undefined, - rendererOptions: { [name: string]: any, }, - indentation?: string, + rendererOptions: { [name: string]: any }, + indentation?: string ): MultiFileRenderResult { if (indentation === undefined) { indentation = this.defaultIndentation; @@ -67,31 +67,31 @@ export abstract class TargetLanguage { return mapMap(renderResult.sources, s => serializeRenderResult(s, renderResult.names, defined(indentation))); } - protected get defaultIndentation (): string { + protected get defaultIndentation(): string { return " "; } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { return new Map(); } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return false; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return false; } - get supportsFullObjectType (): boolean { + public get supportsFullObjectType(): boolean { return false; } - needsTransformerForType (_t: Type): boolean { + public needsTransformerForType(_t: Type): boolean { return false; } - get dateTimeRecognizer (): DateTimeRecognizer { + public get dateTimeRecognizer(): DateTimeRecognizer { return new DefaultDateTimeRecognizer(); } } diff --git a/packages/quicktype-core/src/Transformers.ts b/packages/quicktype-core/src/Transformers.ts index 0b978b771..3c9b3f9eb 100644 --- a/packages/quicktype-core/src/Transformers.ts +++ b/packages/quicktype-core/src/Transformers.ts @@ -6,7 +6,7 @@ import { addHashCode, definedMapWithDefault, arraySortByInto, - hashString, + hashString } from "collection-utils"; import { type Type, type TypeKind } from "./Type"; @@ -17,7 +17,7 @@ import { type BaseGraphRewriteBuilder } from "./GraphRewriting"; import { type TypeRef, type TypeGraph } from "./TypeGraph"; import { derefTypeRef } from "./TypeGraph"; -function debugStringForType (t: Type): string { +function debugStringForType(t: Type): string { const target = followTargetType(t); if (t === target) { return t.kind; @@ -26,126 +26,140 @@ function debugStringForType (t: Type): string { return `${t.kind} (${target.kind})`; } -function getNumberOfNodes (xfer: Transformer | undefined): number { +function getNumberOfNodes(xfer: Transformer | undefined): number { return definedMapWithDefault(xfer, 0, x => x.getNumberOfNodes()); } export abstract class Transformer { - constructor (readonly kind: string, protected readonly graph: TypeGraph, readonly sourceTypeRef: TypeRef) {} + public constructor( + public readonly kind: string, + protected readonly graph: TypeGraph, + public readonly sourceTypeRef: TypeRef + ) {} - get sourceType (): Type { + public get sourceType(): Type { return derefTypeRef(this.sourceTypeRef, this.graph); } /** This must return a newly constructed set. */ - getChildren (): Set { + public getChildren(): Set { return new Set([this.sourceType]); } - getNumberOfNodes (): number { + public getNumberOfNodes(): number { return 1; } - abstract get canFail (): boolean; + public abstract get canFail(): boolean; - abstract reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer; + public abstract reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer; - abstract reconstitute(builder: TBuilder): Transformer; + public abstract reconstitute(builder: TBuilder): Transformer; - equals (other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof Transformer)) return false; return this.sourceTypeRef === other.sourceTypeRef; } - hashCode (): number { + public hashCode(): number { return hashCodeOf(this.sourceTypeRef); } - protected debugDescription (): string { + protected debugDescription(): string { return `${debugStringForType(this.sourceType)} -> ${this.kind}`; } - protected debugPrintContinuations (_indent: number): void { + protected debugPrintContinuations(_indent: number): void { return; } - debugPrint (indent: number): void { + public debugPrint(indent: number): void { console.log(indentationString(indent) + this.debugDescription()); this.debugPrintContinuations(indent + 1); } } export abstract class ProducerTransformer extends Transformer { - constructor (kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, readonly consumer: Transformer | undefined) { + public constructor( + kind: string, + graph: TypeGraph, + sourceTypeRef: TypeRef, + public readonly consumer: Transformer | undefined + ) { super(kind, graph, sourceTypeRef); } - getChildren (): Set { + public getChildren(): Set { const children = super.getChildren(); if (this.consumer === undefined) return children; return setUnionInto(children, this.consumer.getChildren()); } - getNumberOfNodes (): number { + public getNumberOfNodes(): number { return super.getNumberOfNodes() + getNumberOfNodes(this.consumer); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ProducerTransformer)) return false; return areEqual(this.consumer, other.consumer); } - hashCode (): number { + public hashCode(): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.consumer)); } - protected debugPrintContinuations (indent: number): void { + protected debugPrintContinuations(indent: number): void { if (this.consumer === undefined) return; this.consumer.debugPrint(indent); } } export abstract class MatchTransformer extends Transformer { - constructor (kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, readonly transformer: Transformer) { + public constructor( + kind: string, + graph: TypeGraph, + sourceTypeRef: TypeRef, + public readonly transformer: Transformer + ) { super(kind, graph, sourceTypeRef); } - getChildren (): Set { + public getChildren(): Set { return setUnionInto(super.getChildren(), this.transformer.getChildren()); } - getNumberOfNodes (): number { + public getNumberOfNodes(): number { return super.getNumberOfNodes() + this.transformer.getNumberOfNodes(); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof MatchTransformer)) return false; return this.transformer.equals(other.transformer); } - hashCode (): number { + public hashCode(): number { const h = super.hashCode(); return addHashCode(h, this.transformer.hashCode()); } - protected debugPrintContinuations (indent: number): void { + protected debugPrintContinuations(indent: number): void { this.transformer.debugPrint(indent); } } export class DecodingTransformer extends ProducerTransformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + public constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { super("decode", graph, sourceTypeRef, consumer); } - get canFail (): boolean { + public get canFail(): boolean { return false; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer !== undefined) { return panic("Reversing a decoding transformer cannot have a continuation"); } @@ -155,43 +169,43 @@ export class DecodingTransformer extends ProducerTransformer { } else { return this.consumer.reverse( targetTypeRef, - new EncodingTransformer(this.graph, this.consumer.sourceTypeRef), + new EncodingTransformer(this.graph, this.consumer.sourceTypeRef) ); } } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new DecodingTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - definedMap(this.consumer, xfer => xfer.reconstitute(builder)), + definedMap(this.consumer, xfer => xfer.reconstitute(builder)) ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; return other instanceof DecodingTransformer; } } export class EncodingTransformer extends Transformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef) { + public constructor(graph: TypeGraph, sourceTypeRef: TypeRef) { super("encode", graph, sourceTypeRef); } - get canFail (): boolean { + public get canFail(): boolean { return false; } - reverse (_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + public reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { return panic("Can't reverse encoding transformer"); } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new EncodingTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof EncodingTransformer)) return false; return true; @@ -199,35 +213,35 @@ export class EncodingTransformer extends Transformer { } export class ArrayDecodingTransformer extends ProducerTransformer { - constructor ( + public constructor( graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, private readonly _itemTargetTypeRef: TypeRef, - readonly itemTransformer: Transformer, + public readonly itemTransformer: Transformer ) { super("decode-array", graph, sourceTypeRef, consumer); } - getChildren (): Set { + public getChildren(): Set { const children = super.getChildren(); children.add(this.itemTargetType); return setUnionInto(children, this.itemTransformer.getChildren()); } - getNumberOfNodes (): number { + public getNumberOfNodes(): number { return super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes(); } - get canFail (): boolean { + public get canFail(): boolean { return false; } - get itemTargetType (): Type { + public get itemTargetType(): Type { return derefTypeRef(this._itemTargetTypeRef, this.graph); } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer !== undefined) { return panic("Reversing a decoding transformer cannot have a continuation"); } @@ -239,7 +253,7 @@ export class ArrayDecodingTransformer extends ProducerTransformer { this.graph, targetTypeRef, this.itemTransformer.sourceTypeRef, - itemTransformer, + itemTransformer ); } else { return this.consumer.reverse( @@ -248,109 +262,113 @@ export class ArrayDecodingTransformer extends ProducerTransformer { this.graph, this.consumer.sourceTypeRef, this.itemTransformer.sourceTypeRef, - itemTransformer, - ), + itemTransformer + ) ); } } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new ArrayDecodingTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), builder.reconstituteTypeRef(this._itemTargetTypeRef), - this.itemTransformer.reconstitute(builder), + this.itemTransformer.reconstitute(builder) ); } - hashCode (): number { + public hashCode(): number { let h = super.hashCode(); h = addHashCode(h, hashCodeOf(this._itemTargetTypeRef)); h = addHashCode(h, this.itemTransformer.hashCode()); return h; } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ArrayDecodingTransformer)) return false; if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) return false; return this.itemTransformer.equals(other.itemTransformer); } - protected debugPrintContinuations (indent: number): void { + protected debugPrintContinuations(indent: number): void { this.itemTransformer.debugPrint(indent); super.debugPrintContinuations(indent); } } export class ArrayEncodingTransformer extends Transformer { - constructor ( + public constructor( graph: TypeGraph, sourceTypeRef: TypeRef, private readonly _itemTargetTypeRef: TypeRef, - readonly itemTransformer: Transformer, + public readonly itemTransformer: Transformer ) { super("encode-array", graph, sourceTypeRef); } - getChildren (): Set { + public getChildren(): Set { const children = super.getChildren(); children.add(this.itemTargetType); return setUnionInto(children, this.itemTransformer.getChildren()); } - getNumberOfNodes (): number { + public getNumberOfNodes(): number { return super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes(); } - get canFail (): boolean { + public get canFail(): boolean { return false; } - get itemTargetType (): Type { + public get itemTargetType(): Type { return derefTypeRef(this._itemTargetTypeRef, this.graph); } - reverse (_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + public reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { return panic("Can't reverse array encoding transformer"); } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new ArrayEncodingTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), builder.reconstituteTypeRef(this._itemTargetTypeRef), - this.itemTransformer.reconstitute(builder), + this.itemTransformer.reconstitute(builder) ); } - hashCode (): number { + public hashCode(): number { let h = super.hashCode(); h = addHashCode(h, hashCodeOf(this._itemTargetTypeRef)); return addHashCode(h, this.itemTransformer.hashCode()); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ArrayEncodingTransformer)) return false; if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) return false; return this.itemTransformer.equals(other.itemTransformer); } - protected debugPrintContinuations (indent: number): void { + protected debugPrintContinuations(indent: number): void { this.itemTransformer.debugPrint(indent); super.debugPrintContinuations(indent); } } export class ChoiceTransformer extends Transformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef, public readonly transformers: readonly Transformer[]) { + public constructor( + graph: TypeGraph, + sourceTypeRef: TypeRef, + public readonly transformers: readonly Transformer[] + ) { super("choice", graph, sourceTypeRef); assert(transformers.length > 0, "Choice must have at least one transformer"); } - getChildren (): Set { + public getChildren(): Set { let children = super.getChildren(); for (const xfer of this.transformers) { setUnionInto(children, xfer.getChildren()); @@ -359,7 +377,7 @@ export class ChoiceTransformer extends Transformer { return children; } - getNumberOfNodes (): number { + public getNumberOfNodes(): number { let n = 0; for (const xfer of this.transformers) { n += xfer.getNumberOfNodes(); @@ -368,11 +386,11 @@ export class ChoiceTransformer extends Transformer { return super.getNumberOfNodes() + n; } - get canFail (): boolean { + public get canFail(): boolean { return this.transformers.some(xfer => xfer.canFail); } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { const transformers = this.transformers.map(xfer => xfer.reverse(targetTypeRef, continuationTransformer)); if (transformers.every(xfer => xfer instanceof UnionMemberMatchTransformer)) { const memberMatchers = transformers as UnionMemberMatchTransformer[]; @@ -383,7 +401,7 @@ export class ChoiceTransformer extends Transformer { this.graph, targetTypeRef, new ChoiceTransformer(this.graph, subTransformers[0].sourceTypeRef, subTransformers), - first.memberTypeRef, + first.memberTypeRef ); } } @@ -391,26 +409,26 @@ export class ChoiceTransformer extends Transformer { return new ChoiceTransformer(this.graph, targetTypeRef, transformers); } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new ChoiceTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - this.transformers.map(xfer => xfer.reconstitute(builder)), + this.transformers.map(xfer => xfer.reconstitute(builder)) ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof ChoiceTransformer)) return false; return areEqual(this.transformers, other.transformers); } - hashCode (): number { + public hashCode(): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.transformers)); } - protected debugPrintContinuations (indent: number): void { + protected debugPrintContinuations(indent: number): void { for (const xfer of this.transformers) { xfer.debugPrint(indent); } @@ -418,23 +436,23 @@ export class ChoiceTransformer extends Transformer { } export class DecodingChoiceTransformer extends Transformer { - constructor ( + public constructor( graph: TypeGraph, sourceTypeRef: TypeRef, - readonly nullTransformer: Transformer | undefined, - readonly integerTransformer: Transformer | undefined, - readonly doubleTransformer: Transformer | undefined, - readonly boolTransformer: Transformer | undefined, - readonly stringTransformer: Transformer | undefined, - readonly arrayTransformer: Transformer | undefined, - readonly objectTransformer: Transformer | undefined, + public readonly nullTransformer: Transformer | undefined, + public readonly integerTransformer: Transformer | undefined, + public readonly doubleTransformer: Transformer | undefined, + public readonly boolTransformer: Transformer | undefined, + public readonly stringTransformer: Transformer | undefined, + public readonly arrayTransformer: Transformer | undefined, + public readonly objectTransformer: Transformer | undefined ) { super("decoding-choice", graph, sourceTypeRef); } - get transformers (): readonly Transformer[] { + public get transformers(): readonly Transformer[] { const transformers: Transformer[] = []; - function add (xfer: Transformer | undefined) { + function add(xfer: Transformer | undefined) { if (xfer === undefined) return; transformers.push(xfer); } @@ -450,7 +468,7 @@ export class DecodingChoiceTransformer extends Transformer { return transformers; } - getChildren (): Set { + public getChildren(): Set { let children = super.getChildren(); for (const xfer of this.transformers) { setUnionInto(children, xfer.getChildren()); @@ -459,7 +477,7 @@ export class DecodingChoiceTransformer extends Transformer { return children; } - getNumberOfNodes (): number { + public getNumberOfNodes(): number { let n = super.getNumberOfNodes(); for (const xfer of this.transformers) { n += getNumberOfNodes(xfer); @@ -468,20 +486,20 @@ export class DecodingChoiceTransformer extends Transformer { return n; } - get canFail (): boolean { + public get canFail(): boolean { return false; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { assert( continuationTransformer === undefined, - "Reversing a decoding transformer can't have a target transformer", + "Reversing a decoding transformer can't have a target transformer" ); let transformers = new Map(); let memberMatchTransformers = new Map(); - function addCase (reversed: Transformer) { + function addCase(reversed: Transformer) { if (reversed instanceof UnionMemberMatchTransformer) { const memberType = reversed.memberType; let arr = memberMatchTransformers.get(memberType); @@ -503,7 +521,7 @@ export class DecodingChoiceTransformer extends Transformer { } } - function reverseAndAdd (transformer: Transformer) { + function reverseAndAdd(transformer: Transformer) { const reversed = transformer.reverse(targetTypeRef, undefined); let cases: readonly Transformer[] = []; // Flatten nested ChoiceTransformers @@ -525,7 +543,7 @@ export class DecodingChoiceTransformer extends Transformer { // If there are non-failing transformers, we ignore the ones that can fail and // just pick the "simplest" non-failing one, being the one with the least number // of nodes. - function filter (xfers: Transformer[]): Transformer[] { + function filter(xfers: Transformer[]): Transformer[] { assert(xfers.length > 0, "Must have at least one transformer"); const nonfailing = xfers.filter(xfer => { @@ -544,7 +562,7 @@ export class DecodingChoiceTransformer extends Transformer { const smallest = arraySortByInto( nonfailing.map(x => [x.getNumberOfNodes(), x] as [number, Transformer]), - ([c, _]) => c, + ([c, _]) => c )[0][1]; return [smallest]; } @@ -562,8 +580,8 @@ export class DecodingChoiceTransformer extends Transformer { return new ChoiceTransformer(this.graph, targetTypeRef, resultingTransformers); } - reconstitute(builder: TBuilder): Transformer { - function reconstitute (xf: Transformer | undefined) { + public reconstitute(builder: TBuilder): Transformer { + function reconstitute(xf: Transformer | undefined) { if (xf === undefined) return undefined; return xf.reconstitute(builder); } @@ -577,11 +595,11 @@ export class DecodingChoiceTransformer extends Transformer { reconstitute(this.boolTransformer), reconstitute(this.stringTransformer), reconstitute(this.arrayTransformer), - reconstitute(this.objectTransformer), + reconstitute(this.objectTransformer) ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof DecodingChoiceTransformer)) return false; if (!areEqual(this.nullTransformer, other.nullTransformer)) return false; @@ -594,7 +612,7 @@ export class DecodingChoiceTransformer extends Transformer { return true; } - hashCode (): number { + public hashCode(): number { let h = super.hashCode(); h = addHashCode(h, hashCodeOf(this.nullTransformer)); h = addHashCode(h, hashCodeOf(this.integerTransformer)); @@ -606,7 +624,7 @@ export class DecodingChoiceTransformer extends Transformer { return h; } - protected debugPrintContinuations (indent: number): void { + protected debugPrintContinuations(indent: number): void { for (const xfer of this.transformers) { xfer.debugPrint(indent); } @@ -614,11 +632,16 @@ export class DecodingChoiceTransformer extends Transformer { } export class UnionMemberMatchTransformer extends MatchTransformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, readonly memberTypeRef: TypeRef) { + public constructor( + graph: TypeGraph, + sourceTypeRef: TypeRef, + transformer: Transformer, + public readonly memberTypeRef: TypeRef + ) { super("union-member-match", graph, sourceTypeRef, transformer); } - get sourceType (): UnionType { + public get sourceType(): UnionType { const t = derefTypeRef(this.sourceTypeRef, this.graph); if (!(t instanceof UnionType)) { return panic("The source of a union member match transformer must be a union type"); @@ -627,43 +650,43 @@ export class UnionMemberMatchTransformer extends MatchTransformer { return t; } - get canFail (): boolean { + public get canFail(): boolean { return true; } - get memberType (): Type { + public get memberType(): Type { return derefTypeRef(this.memberTypeRef, this.graph); } - getChildren (): Set { + public getChildren(): Set { return super.getChildren().add(this.memberType); } - reverse (_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + public reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { return panic("Can't reverse union member match transformer"); } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new UnionMemberMatchTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), this.transformer.reconstitute(builder), - builder.reconstituteTypeRef(this.memberTypeRef), + builder.reconstituteTypeRef(this.memberTypeRef) ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof UnionMemberMatchTransformer)) return false; return this.memberTypeRef === other.memberTypeRef; } - hashCode (): number { + public hashCode(): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.memberTypeRef)); } - protected debugDescription (): string { + protected debugDescription(): string { return `${super.debugDescription()} - member: ${debugStringForType(this.memberType)}`; } } @@ -672,11 +695,16 @@ export class UnionMemberMatchTransformer extends MatchTransformer { * This matches strings and enum cases. */ export class StringMatchTransformer extends MatchTransformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, readonly stringCase: string) { + public constructor( + graph: TypeGraph, + sourceTypeRef: TypeRef, + transformer: Transformer, + public readonly stringCase: string + ) { super("string-match", graph, sourceTypeRef, transformer); } - get sourceType (): EnumType | PrimitiveType { + public get sourceType(): EnumType | PrimitiveType { const t = derefTypeRef(this.sourceTypeRef, this.graph); if (!(t instanceof EnumType) && !(t instanceof PrimitiveType && t.kind === "string")) { return panic("The source of a string match transformer must be an enum or string type"); @@ -685,57 +713,57 @@ export class StringMatchTransformer extends MatchTransformer { return t; } - get canFail (): boolean { + public get canFail(): boolean { return true; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { return this.transformer.reverse( targetTypeRef, new StringProducerTransformer( this.graph, this.transformer.sourceTypeRef, continuationTransformer, - this.stringCase, - ), + this.stringCase + ) ); } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new StringMatchTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), this.transformer.reconstitute(builder), - this.stringCase, + this.stringCase ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof StringMatchTransformer)) return false; return this.stringCase !== other.stringCase; } - hashCode (): number { + public hashCode(): number { const h = super.hashCode(); return addHashCode(h, hashString(this.stringCase)); } - protected debugDescription (): string { + protected debugDescription(): string { return `${super.debugDescription()} - case: ${this.stringCase}`; } } export class UnionInstantiationTransformer extends Transformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef) { + public constructor(graph: TypeGraph, sourceTypeRef: TypeRef) { super("union-instantiation", graph, sourceTypeRef); } - get canFail (): boolean { + public get canFail(): boolean { return false; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer === undefined) { return panic("Union instantiation transformer reverse must have a continuation"); } @@ -743,11 +771,11 @@ export class UnionInstantiationTransformer extends Transformer { return new UnionMemberMatchTransformer(this.graph, targetTypeRef, continuationTransformer, this.sourceTypeRef); } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new UnionInstantiationTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; return other instanceof UnionInstantiationTransformer; } @@ -757,15 +785,20 @@ export class UnionInstantiationTransformer extends Transformer { * Produces a string or an enum case. */ export class StringProducerTransformer extends ProducerTransformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, readonly result: string) { + public constructor( + graph: TypeGraph, + sourceTypeRef: TypeRef, + consumer: Transformer | undefined, + public readonly result: string + ) { super("string-producer", graph, sourceTypeRef, consumer); } - get canFail (): boolean { + public get canFail(): boolean { return false; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (continuationTransformer === undefined) { return panic("Reversing a string producer transformer must have a continuation"); } @@ -779,128 +812,128 @@ export class StringProducerTransformer extends ProducerTransformer { this.graph, this.consumer.sourceTypeRef, continuationTransformer, - this.result, - ), + this.result + ) ); } } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new StringProducerTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), - this.result, + this.result ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; if (!(other instanceof StringProducerTransformer)) return false; return this.result === other.result; } - hashCode (): number { + public hashCode(): number { const h = super.hashCode(); return addHashCode(h, hashCodeOf(this.consumer)); } - protected debugDescription (): string { + protected debugDescription(): string { return `${super.debugDescription()} - result: ${this.result}`; } } export class ParseStringTransformer extends ProducerTransformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + public constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { super("parse-string", graph, sourceTypeRef, consumer); } - get canFail (): boolean { + public get canFail(): boolean { return true; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new StringifyTransformer(this.graph, targetTypeRef, continuationTransformer); } else { return this.consumer.reverse( targetTypeRef, - new StringifyTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer), + new StringifyTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer) ); } } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new ParseStringTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - definedMap(this.consumer, xfer => xfer.reconstitute(builder)), + definedMap(this.consumer, xfer => xfer.reconstitute(builder)) ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; return other instanceof ParseStringTransformer; } } export class StringifyTransformer extends ProducerTransformer { - constructor (graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + public constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { super("stringify", graph, sourceTypeRef, consumer); } - get canFail (): boolean { + public get canFail(): boolean { return false; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new ParseStringTransformer(this.graph, targetTypeRef, continuationTransformer); } else { return this.consumer.reverse( targetTypeRef, - new ParseStringTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer), + new ParseStringTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer) ); } } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new StringifyTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), - definedMap(this.consumer, xfer => xfer.reconstitute(builder)), + definedMap(this.consumer, xfer => xfer.reconstitute(builder)) ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; return other instanceof StringifyTransformer; } } export class MinMaxLengthCheckTransformer extends ProducerTransformer { - constructor ( + public constructor( graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, - readonly minLength: number | undefined, - readonly maxLength: number | undefined, + public readonly minLength: number | undefined, + public readonly maxLength: number | undefined ) { super("min-max-length-check", graph, sourceTypeRef, consumer); } - get canFail (): boolean { + public get canFail(): boolean { return true; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new MinMaxLengthCheckTransformer( this.graph, targetTypeRef, continuationTransformer, this.minLength, - this.maxLength, + this.maxLength ); } else { return this.consumer.reverse( @@ -910,23 +943,23 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { this.consumer.sourceTypeRef, continuationTransformer, this.minLength, - this.maxLength, - ), + this.maxLength + ) ); } } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new MinMaxLengthCheckTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), this.minLength, - this.maxLength, + this.maxLength ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; return ( other instanceof MinMaxLengthCheckTransformer && @@ -937,28 +970,28 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { } export class MinMaxValueTransformer extends ProducerTransformer { - constructor ( + public constructor( graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, - readonly minimum: number | undefined, - readonly maximum: number | undefined, + public readonly minimum: number | undefined, + public readonly maximum: number | undefined ) { super("min-max-value-check", graph, sourceTypeRef, consumer); } - get canFail (): boolean { + public get canFail(): boolean { return true; } - reverse (targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { + public reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer { if (this.consumer === undefined) { return new MinMaxValueTransformer( this.graph, targetTypeRef, continuationTransformer, this.minimum, - this.maximum, + this.maximum ); } else { return this.consumer.reverse( @@ -968,23 +1001,23 @@ export class MinMaxValueTransformer extends ProducerTransformer { this.consumer.sourceTypeRef, continuationTransformer, this.minimum, - this.maximum, - ), + this.maximum + ) ); } } - reconstitute(builder: TBuilder): Transformer { + public reconstitute(builder: TBuilder): Transformer { return new MinMaxValueTransformer( builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef), definedMap(this.consumer, xfer => xfer.reconstitute(builder)), this.minimum, - this.maximum, + this.maximum ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!super.equals(other)) return false; return ( other instanceof MinMaxValueTransformer && this.minimum === other.minimum && this.maximum === other.maximum @@ -993,90 +1026,93 @@ export class MinMaxValueTransformer extends ProducerTransformer { } export class Transformation { - constructor ( + public constructor( private readonly _graph: TypeGraph, private readonly _targetTypeRef: TypeRef, - readonly transformer: Transformer, + public readonly transformer: Transformer ) {} - get sourceType (): Type { + public get sourceType(): Type { return this.transformer.sourceType; } - get targetType (): Type { + public get targetType(): Type { return derefTypeRef(this._targetTypeRef, this._graph); } - get reverse (): Transformation { + public get reverse(): Transformation { return new Transformation( this._graph, this.transformer.sourceTypeRef, - this.transformer.reverse(this._targetTypeRef, undefined), + this.transformer.reverse(this._targetTypeRef, undefined) ); } - getChildren (): Set { + public getChildren(): Set { return this.transformer.getChildren().add(this.targetType); } - reconstitute(builder: TBuilder): Transformation { + public reconstitute(builder: TBuilder): Transformation { return new Transformation( builder.typeGraph, builder.reconstituteTypeRef(this._targetTypeRef), - this.transformer.reconstitute(builder), + this.transformer.reconstitute(builder) ); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof Transformation)) return false; return this._targetTypeRef === other._targetTypeRef && this.transformer.equals(other.transformer); } - hashCode (): number { + public hashCode(): number { let h = hashCodeOf(this._targetTypeRef); h = addHashCode(h, this.transformer.hashCode()); return h; } - debugPrint (): void { + public debugPrint(): void { this.transformer.debugPrint(0); console.log(`-> ${debugStringForType(this.targetType)}`); } } class TransformationTypeAttributeKind extends TypeAttributeKind { - constructor () { + public constructor() { super("transformation"); } - appliesToTypeKind (_kind: TypeKind): boolean { + public appliesToTypeKind(_kind: TypeKind): boolean { return true; } - get inIdentity (): boolean { + public get inIdentity(): boolean { return true; } - children (xf: Transformation): Set { + public children(xf: Transformation): Set { return xf.getChildren(); } - reconstitute(builder: TBuilder, xf: Transformation): Transformation { + public reconstitute( + builder: TBuilder, + xf: Transformation + ): Transformation { return xf.reconstitute(builder); } - stringify (_: Transformation): string { + public stringify(_: Transformation): string { return "transformation"; } } export const transformationTypeAttributeKind: TypeAttributeKind = new TransformationTypeAttributeKind(); -export function transformationForType (t: Type): Transformation | undefined { +export function transformationForType(t: Type): Transformation | undefined { return transformationTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } -export function followTargetType (t: Type): Type { +export function followTargetType(t: Type): Type { for (;;) { const xf = transformationForType(t); if (xf === undefined) return t; diff --git a/packages/quicktype-core/src/Type.ts b/packages/quicktype-core/src/Type.ts index 6c6542e08..6b50cd7d9 100644 --- a/packages/quicktype-core/src/Type.ts +++ b/packages/quicktype-core/src/Type.ts @@ -18,16 +18,16 @@ import { hashCodeInit, addHashCode, hasOwnProperty, - mapFromObject, + mapFromObject } from "collection-utils"; import { defined, panic, assert } from "./support/Support"; import { type TypeReconstituter, type BaseGraphRewriteBuilder } from "./GraphRewriting"; -import { type TypeNames} from "./attributes/TypeNames"; +import { type TypeNames } from "./attributes/TypeNames"; import { namesTypeAttributeKind } from "./attributes/TypeNames"; import { type TypeAttributes } from "./attributes/TypeAttributes"; import { messageAssert } from "./Messages"; -import { type TypeRef, type TypeGraph} from "./TypeGraph"; +import { type TypeRef, type TypeGraph } from "./TypeGraph"; import { attributesForTypeRef, derefTypeRef, typeRefIndex } from "./TypeGraph"; import { uriInferenceAttributesProducer } from "./attributes/URIAttributes"; @@ -58,13 +58,13 @@ const transformedStringTypeTargetTypeKinds = { uuid: { jsonSchema: "uuid", primitive: undefined }, uri: { jsonSchema: "uri", primitive: undefined, attributesProducer: uriInferenceAttributesProducer }, "integer-string": { jsonSchema: "integer", primitive: "integer" } as TransformedStringTypeTargets, - "bool-string": { jsonSchema: "boolean", primitive: "bool" } as TransformedStringTypeTargets, + "bool-string": { jsonSchema: "boolean", primitive: "bool" } as TransformedStringTypeTargets }; export const transformedStringTypeTargetTypeKindsMap = mapFromObject( transformedStringTypeTargetTypeKinds as { - [kind: string]: TransformedStringTypeTargets, - }, + [kind: string]: TransformedStringTypeTargets; + } ); export type TransformedStringTypeKind = keyof typeof transformedStringTypeTargetTypeKinds; @@ -76,32 +76,32 @@ export type TypeKind = PrimitiveTypeKind | NamedTypeKind | "array" | "object" | export type ObjectTypeKind = "object" | "map" | "class"; export const transformedStringTypeKinds = new Set( - Object.getOwnPropertyNames(transformedStringTypeTargetTypeKinds), + Object.getOwnPropertyNames(transformedStringTypeTargetTypeKinds) ) as ReadonlySet; -export function isPrimitiveStringTypeKind (kind: string): kind is PrimitiveStringTypeKind { +export function isPrimitiveStringTypeKind(kind: string): kind is PrimitiveStringTypeKind { return kind === "string" || hasOwnProperty(transformedStringTypeTargetTypeKinds, kind); } -export function targetTypeKindForTransformedStringTypeKind ( - kind: PrimitiveStringTypeKind, +export function targetTypeKindForTransformedStringTypeKind( + kind: PrimitiveStringTypeKind ): PrimitiveNonStringTypeKind | undefined { const target = transformedStringTypeTargetTypeKindsMap.get(kind); if (target === undefined) return undefined; return target.primitive; } -export function isNumberTypeKind (kind: TypeKind): kind is "integer" | "double" { +export function isNumberTypeKind(kind: TypeKind): kind is "integer" | "double" { return kind === "integer" || kind === "double"; } -export function isPrimitiveTypeKind (kind: TypeKind): kind is PrimitiveTypeKind { +export function isPrimitiveTypeKind(kind: TypeKind): kind is PrimitiveTypeKind { if (isPrimitiveStringTypeKind(kind)) return true; if (isNumberTypeKind(kind)) return true; return kind === "none" || kind === "any" || kind === "null" || kind === "bool"; } -function triviallyStructurallyCompatible (x: Type, y: Type): boolean { +function triviallyStructurallyCompatible(x: Type, y: Type): boolean { if (x.index === y.index) return true; if (x.kind === "none" || y.kind === "none") return true; return false; @@ -110,7 +110,10 @@ function triviallyStructurallyCompatible (x: Type, y: Type): boolean { export class TypeIdentity { private readonly _hashCode: number; - constructor (private readonly _kind: TypeKind, private readonly _components: readonly any[]) { + public constructor( + private readonly _kind: TypeKind, + private readonly _components: readonly any[] + ) { let h = hashCodeInit; h = addHashCode(h, hashCodeOf(this._kind)); for (const c of _components) { @@ -120,7 +123,7 @@ export class TypeIdentity { this._hashCode = h; } - equals (other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof TypeIdentity)) return false; if (this._kind !== other._kind) return false; const n = this._components.length; @@ -132,7 +135,7 @@ export class TypeIdentity { return true; } - hashCode (): number { + public hashCode(): number { return this._hashCode; } } @@ -141,18 +144,21 @@ export class TypeIdentity { export type MaybeTypeIdentity = TypeIdentity | undefined; export abstract class Type { - abstract readonly kind: TypeKind; + public abstract readonly kind: TypeKind; - constructor (readonly typeRef: TypeRef, protected readonly graph: TypeGraph) {} + public constructor( + public readonly typeRef: TypeRef, + protected readonly graph: TypeGraph + ) {} - get index (): number { + public get index(): number { return typeRefIndex(this.typeRef); } // This must return a newly allocated set - abstract getNonAttributeChildren (): Set; + public abstract getNonAttributeChildren(): Set; - getChildren (): ReadonlySet { + public getChildren(): ReadonlySet { let result = this.getNonAttributeChildren(); for (const [k, v] of this.getAttributes()) { if (k.children === undefined) continue; @@ -162,54 +168,54 @@ export abstract class Type { return result; } - getAttributes (): TypeAttributes { + public getAttributes(): TypeAttributes { return attributesForTypeRef(this.typeRef, this.graph); } - get hasNames (): boolean { + public get hasNames(): boolean { return namesTypeAttributeKind.tryGetInAttributes(this.getAttributes()) !== undefined; } - getNames (): TypeNames { + public getNames(): TypeNames { return defined(namesTypeAttributeKind.tryGetInAttributes(this.getAttributes())); } - getCombinedName (): string { + public getCombinedName(): string { return this.getNames().combinedName; } - abstract get isNullable (): boolean; + public abstract get isNullable(): boolean; // FIXME: Remove `isPrimitive` - abstract isPrimitive (): this is PrimitiveType; - abstract get identity (): MaybeTypeIdentity; - abstract reconstitute( + public abstract isPrimitive(): this is PrimitiveType; + public abstract get identity(): MaybeTypeIdentity; + public abstract reconstitute( builder: TypeReconstituter, canonicalOrder: boolean ): void; - get debugPrintKind (): string { + public get debugPrintKind(): string { return this.kind; } - equals (other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof Type)) return false; return this.typeRef === other.typeRef; } - hashCode (): number { + public hashCode(): number { return hashCodeOf(this.typeRef); } // This will only ever be called when `this` and `other` are not // equal, but `this.kind === other.kind`. - protected abstract structuralEqualityStep ( + protected abstract structuralEqualityStep( other: Type, conflateNumbers: boolean, queue: (a: Type, b: Type) => boolean ): boolean; - structurallyCompatible (other: Type, conflateNumbers = false): boolean { - function kindsCompatible (kind1: TypeKind, kind2: TypeKind): boolean { + public structurallyCompatible(other: Type, conflateNumbers = false): boolean { + function kindsCompatible(kind1: TypeKind, kind2: TypeKind): boolean { if (kind1 === kind2) return true; if (!conflateNumbers) return false; if (kind1 === "integer") return kind2 === "double"; @@ -268,11 +274,11 @@ export abstract class Type { return true; } - getParentTypes (): ReadonlySet { + public getParentTypes(): ReadonlySet { return this.graph.getParentsOfType(this); } - getAncestorsNotInSet (set: ReadonlySet): ReadonlySet { + public getAncestorsNotInSet(set: ReadonlySet): ReadonlySet { const workList: Type[] = [this]; const processed = new Set(); const ancestors = new Set(); @@ -299,54 +305,58 @@ export abstract class Type { } } -function hasUniqueIdentityAttributes (attributes: TypeAttributes): boolean { +function hasUniqueIdentityAttributes(attributes: TypeAttributes): boolean { return mapSome(attributes, (v, ta) => ta.requiresUniqueIdentity(v)); } -function identityAttributes (attributes: TypeAttributes): TypeAttributes { +function identityAttributes(attributes: TypeAttributes): TypeAttributes { return mapFilter(attributes, (_, kind) => kind.inIdentity); } -export function primitiveTypeIdentity (kind: PrimitiveTypeKind, attributes: TypeAttributes): MaybeTypeIdentity { +export function primitiveTypeIdentity(kind: PrimitiveTypeKind, attributes: TypeAttributes): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity(kind, [identityAttributes(attributes)]); } export class PrimitiveType extends Type { - constructor (typeRef: TypeRef, graph: TypeGraph, public readonly kind: PrimitiveTypeKind) { + public constructor( + typeRef: TypeRef, + graph: TypeGraph, + public readonly kind: PrimitiveTypeKind + ) { super(typeRef, graph); } - get isNullable (): boolean { + public get isNullable(): boolean { return this.kind === "null" || this.kind === "any" || this.kind === "none"; } - isPrimitive (): this is PrimitiveType { + public isPrimitive(): this is PrimitiveType { return true; } - getNonAttributeChildren (): Set { + public getNonAttributeChildren(): Set { return new Set(); } - get identity (): MaybeTypeIdentity { + public get identity(): MaybeTypeIdentity { return primitiveTypeIdentity(this.kind, this.getAttributes()); } - reconstitute(builder: TypeReconstituter): void { + public reconstitute(builder: TypeReconstituter): void { builder.getPrimitiveType(this.kind); } - protected structuralEqualityStep ( + protected structuralEqualityStep( _other: Type, _conflateNumbers: boolean, - _queue: (a: Type, b: Type) => boolean, + _queue: (a: Type, b: Type) => boolean ): boolean { return true; } } -export function arrayTypeIdentity (attributes: TypeAttributes, itemsRef: TypeRef): MaybeTypeIdentity { +export function arrayTypeIdentity(attributes: TypeAttributes, itemsRef: TypeRef): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity("array", [identityAttributes(attributes), itemsRef]); } @@ -354,11 +364,15 @@ export function arrayTypeIdentity (attributes: TypeAttributes, itemsRef: TypeRef export class ArrayType extends Type { public readonly kind = "array"; - constructor (typeRef: TypeRef, graph: TypeGraph, private _itemsRef?: TypeRef) { + public constructor( + typeRef: TypeRef, + graph: TypeGraph, + private _itemsRef?: TypeRef + ) { super(typeRef, graph); } - setItems (itemsRef: TypeRef) { + public setItems(itemsRef: TypeRef) { if (this._itemsRef !== undefined) { return panic("Can only set array items once"); } @@ -366,7 +380,7 @@ export class ArrayType extends Type { this._itemsRef = itemsRef; } - private getItemsRef (): TypeRef { + private getItemsRef(): TypeRef { if (this._itemsRef === undefined) { return panic("Array items accessed before they were set"); } @@ -374,27 +388,27 @@ export class ArrayType extends Type { return this._itemsRef; } - get items (): Type { + public get items(): Type { return derefTypeRef(this.getItemsRef(), this.graph); } - getNonAttributeChildren (): Set { + public getNonAttributeChildren(): Set { return new Set([this.items]); } - get isNullable (): boolean { + public get isNullable(): boolean { return false; } - isPrimitive (): this is PrimitiveType { + public isPrimitive(): this is PrimitiveType { return false; } - get identity (): MaybeTypeIdentity { + public get identity(): MaybeTypeIdentity { return arrayTypeIdentity(this.getAttributes(), this.getItemsRef()); } - reconstitute(builder: TypeReconstituter): void { + public reconstitute(builder: TypeReconstituter): void { const itemsRef = this.getItemsRef(); const maybeItems = builder.lookup(itemsRef); if (maybeItems === undefined) { @@ -405,19 +419,22 @@ export class ArrayType extends Type { } } - protected structuralEqualityStep ( + protected structuralEqualityStep( other: ArrayType, _conflateNumbers: boolean, - queue: (a: Type, b: Type) => boolean, + queue: (a: Type, b: Type) => boolean ): boolean { return queue(this.items, other.items); } } export class GenericClassProperty { - constructor (readonly typeData: T, readonly isOptional: boolean) {} + public constructor( + public readonly typeData: T, + public readonly isOptional: boolean + ) {} - equals (other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof GenericClassProperty)) { return false; } @@ -425,57 +442,61 @@ export class GenericClassProperty { return areEqual(this.typeData, other.typeData) && this.isOptional === other.isOptional; } - hashCode (): number { + public hashCode(): number { return hashCodeOf(this.typeData) + (this.isOptional ? 17 : 23); } } export class ClassProperty extends GenericClassProperty { - constructor (typeRef: TypeRef, readonly graph: TypeGraph, isOptional: boolean) { + public constructor( + typeRef: TypeRef, + public readonly graph: TypeGraph, + isOptional: boolean + ) { super(typeRef, isOptional); } - get typeRef (): TypeRef { + public get typeRef(): TypeRef { return this.typeData; } - get type (): Type { + public get type(): Type { return derefTypeRef(this.typeRef, this.graph); } } -function objectTypeIdentify ( +function objectTypeIdentify( kind: ObjectTypeKind, attributes: TypeAttributes, properties: ReadonlyMap, - additionalPropertiesRef: TypeRef | undefined, + additionalPropertiesRef: TypeRef | undefined ): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity(kind, [identityAttributes(attributes), properties, additionalPropertiesRef]); } -export function classTypeIdentity ( +export function classTypeIdentity( attributes: TypeAttributes, - properties: ReadonlyMap, + properties: ReadonlyMap ): MaybeTypeIdentity { return objectTypeIdentify("class", attributes, properties, undefined); } -export function mapTypeIdentify ( +export function mapTypeIdentify( attributes: TypeAttributes, - additionalPropertiesRef: TypeRef | undefined, + additionalPropertiesRef: TypeRef | undefined ): MaybeTypeIdentity { return objectTypeIdentify("map", attributes, new Map(), additionalPropertiesRef); } export class ObjectType extends Type { - constructor ( + public constructor( typeRef: TypeRef, graph: TypeGraph, public readonly kind: ObjectTypeKind, - readonly isFixed: boolean, + public readonly isFixed: boolean, private _properties: ReadonlyMap | undefined, - private _additionalPropertiesRef: TypeRef | undefined, + private _additionalPropertiesRef: TypeRef | undefined ) { super(typeRef, graph); @@ -492,7 +513,7 @@ export class ObjectType extends Type { } } - setProperties (properties: ReadonlyMap, additionalPropertiesRef: TypeRef | undefined) { + public setProperties(properties: ReadonlyMap, additionalPropertiesRef: TypeRef | undefined) { assert(this._properties === undefined, "Tried to set object properties twice"); if (this instanceof MapType) { @@ -507,26 +528,26 @@ export class ObjectType extends Type { this._additionalPropertiesRef = additionalPropertiesRef; } - getProperties (): ReadonlyMap { + public getProperties(): ReadonlyMap { return defined(this._properties); } - getSortedProperties (): ReadonlyMap { + public getSortedProperties(): ReadonlyMap { return mapSortByKey(this.getProperties()); } - private getAdditionalPropertiesRef (): TypeRef | undefined { + private getAdditionalPropertiesRef(): TypeRef | undefined { assert(this._properties !== undefined, "Properties are not set yet"); return this._additionalPropertiesRef; } - getAdditionalProperties (): Type | undefined { + public getAdditionalProperties(): Type | undefined { const tref = this.getAdditionalPropertiesRef(); if (tref === undefined) return undefined; return derefTypeRef(tref, this.graph); } - getNonAttributeChildren (): Set { + public getNonAttributeChildren(): Set { const types = mapSortToArray(this.getProperties(), (_, k) => k).map(([_, p]) => p.type); const additionalProperties = this.getAdditionalProperties(); if (additionalProperties !== undefined) { @@ -536,25 +557,28 @@ export class ObjectType extends Type { return new Set(types); } - get isNullable (): boolean { + public get isNullable(): boolean { return false; } - isPrimitive (): this is PrimitiveType { + public isPrimitive(): this is PrimitiveType { return false; } - get identity (): MaybeTypeIdentity { + public get identity(): MaybeTypeIdentity { if (this.isFixed) return undefined; return objectTypeIdentify( this.kind, this.getAttributes(), this.getProperties(), - this.getAdditionalPropertiesRef(), + this.getAdditionalPropertiesRef() ); } - reconstitute(builder: TypeReconstituter, canonicalOrder: boolean): void { + public reconstitute( + builder: TypeReconstituter, + canonicalOrder: boolean + ): void { const sortedProperties = this.getSortedProperties(); const propertiesInNewOrder = canonicalOrder ? sortedProperties : this.getProperties(); const maybePropertyTypes = builder.lookupMap(mapMap(sortedProperties, cp => cp.typeRef)); @@ -565,7 +589,7 @@ export class ObjectType extends Type { (maybeAdditionalProperties !== undefined || this._additionalPropertiesRef === undefined) ) { const properties = mapMap(propertiesInNewOrder, (cp, n) => - builder.makeClassProperty(defined(maybePropertyTypes.get(n)), cp.isOptional), + builder.makeClassProperty(defined(maybePropertyTypes.get(n)), cp.isOptional) ); switch (this.kind) { @@ -605,17 +629,17 @@ export class ObjectType extends Type { const reconstitutedTypes = mapMap(sortedProperties, cp => builder.reconstitute(cp.typeRef)); const properties = mapMap(propertiesInNewOrder, (cp, n) => - builder.makeClassProperty(defined(reconstitutedTypes.get(n)), cp.isOptional), + builder.makeClassProperty(defined(reconstitutedTypes.get(n)), cp.isOptional) ); const additionalProperties = definedMap(this._additionalPropertiesRef, r => builder.reconstitute(r)); builder.setObjectProperties(properties, additionalProperties); } } - protected structuralEqualityStep ( + protected structuralEqualityStep( other: ObjectType, _conflateNumbers: boolean, - queue: (a: Type, b: Type) => boolean, + queue: (a: Type, b: Type) => boolean ): boolean { const pa = this.getProperties(); const pb = other.getProperties(); @@ -633,42 +657,42 @@ export class ObjectType extends Type { const thisAdditionalProperties = this.getAdditionalProperties(); const otherAdditionalProperties = other.getAdditionalProperties(); - if (thisAdditionalProperties === undefined !== (otherAdditionalProperties === undefined)) return false; + if ((thisAdditionalProperties === undefined) !== (otherAdditionalProperties === undefined)) return false; if (thisAdditionalProperties === undefined || otherAdditionalProperties === undefined) return true; return queue(thisAdditionalProperties, otherAdditionalProperties); } } export class ClassType extends ObjectType { - constructor ( + public constructor( typeRef: TypeRef, graph: TypeGraph, isFixed: boolean, - properties: ReadonlyMap | undefined, + properties: ReadonlyMap | undefined ) { super(typeRef, graph, "class", isFixed, properties, undefined); } } export class MapType extends ObjectType { - constructor (typeRef: TypeRef, graph: TypeGraph, valuesRef: TypeRef | undefined) { + public constructor(typeRef: TypeRef, graph: TypeGraph, valuesRef: TypeRef | undefined) { super( typeRef, graph, "map", false, definedMap(valuesRef, () => new Map()), - valuesRef, + valuesRef ); } // FIXME: Remove and use `getAdditionalProperties()` instead. - get values (): Type { + public get values(): Type { return defined(this.getAdditionalProperties()); } } -export function enumTypeIdentity (attributes: TypeAttributes, cases: ReadonlySet): MaybeTypeIdentity { +export function enumTypeIdentity(attributes: TypeAttributes, cases: ReadonlySet): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity("enum", [identityAttributes(attributes), cases]); } @@ -676,44 +700,48 @@ export function enumTypeIdentity (attributes: TypeAttributes, cases: ReadonlySet export class EnumType extends Type { public readonly kind = "enum"; - constructor (typeRef: TypeRef, graph: TypeGraph, readonly cases: ReadonlySet) { + public constructor( + typeRef: TypeRef, + graph: TypeGraph, + public readonly cases: ReadonlySet + ) { super(typeRef, graph); } - get isNullable (): boolean { + public get isNullable(): boolean { return false; } - isPrimitive (): this is PrimitiveType { + public isPrimitive(): this is PrimitiveType { return false; } - get identity (): MaybeTypeIdentity { + public get identity(): MaybeTypeIdentity { return enumTypeIdentity(this.getAttributes(), this.cases); } - getNonAttributeChildren (): Set { + public getNonAttributeChildren(): Set { return new Set(); } - reconstitute(builder: TypeReconstituter): void { + public reconstitute(builder: TypeReconstituter): void { builder.getEnumType(this.cases); } - protected structuralEqualityStep ( + protected structuralEqualityStep( other: EnumType, _conflateNumbers: boolean, - _queue: (a: Type, b: Type) => void, + _queue: (a: Type, b: Type) => void ): boolean { return areEqual(this.cases, other.cases); } } -export function setOperationCasesEqual ( +export function setOperationCasesEqual( typesA: Iterable, typesB: Iterable, conflateNumbers: boolean, - membersEqual: (a: Type, b: Type) => boolean, + membersEqual: (a: Type, b: Type) => boolean ): boolean { const ma = toReadonlySet(typesA); const mb = toReadonlySet(typesB); @@ -733,37 +761,37 @@ export function setOperationCasesEqual ( }); } -export function setOperationTypeIdentity ( +export function setOperationTypeIdentity( kind: TypeKind, attributes: TypeAttributes, - memberRefs: ReadonlySet, + memberRefs: ReadonlySet ): MaybeTypeIdentity { if (hasUniqueIdentityAttributes(attributes)) return undefined; return new TypeIdentity(kind, [identityAttributes(attributes), memberRefs]); } -export function unionTypeIdentity (attributes: TypeAttributes, memberRefs: ReadonlySet): MaybeTypeIdentity { +export function unionTypeIdentity(attributes: TypeAttributes, memberRefs: ReadonlySet): MaybeTypeIdentity { return setOperationTypeIdentity("union", attributes, memberRefs); } -export function intersectionTypeIdentity ( +export function intersectionTypeIdentity( attributes: TypeAttributes, - memberRefs: ReadonlySet, + memberRefs: ReadonlySet ): MaybeTypeIdentity { return setOperationTypeIdentity("intersection", attributes, memberRefs); } export abstract class SetOperationType extends Type { - constructor ( + public constructor( typeRef: TypeRef, graph: TypeGraph, public readonly kind: TypeKind, - private _memberRefs?: ReadonlySet, + private _memberRefs?: ReadonlySet ) { super(typeRef, graph); } - setMembers (memberRefs: ReadonlySet): void { + public setMembers(memberRefs: ReadonlySet): void { if (this._memberRefs !== undefined) { return panic("Can only set map members once"); } @@ -771,7 +799,7 @@ export abstract class SetOperationType extends Type { this._memberRefs = memberRefs; } - protected getMemberRefs (): ReadonlySet { + protected getMemberRefs(): ReadonlySet { if (this._memberRefs === undefined) { return panic("Map members accessed before they were set"); } @@ -779,31 +807,31 @@ export abstract class SetOperationType extends Type { return this._memberRefs; } - get members (): ReadonlySet { + public get members(): ReadonlySet { return setMap(this.getMemberRefs(), tref => derefTypeRef(tref, this.graph)); } - get sortedMembers (): ReadonlySet { + public get sortedMembers(): ReadonlySet { return this.getNonAttributeChildren(); } - getNonAttributeChildren (): Set { + public getNonAttributeChildren(): Set { // FIXME: We're assuming no two members of the same kind. return setSortBy(this.members, t => t.kind); } - isPrimitive (): this is PrimitiveType { + public isPrimitive(): this is PrimitiveType { return false; } - get identity (): MaybeTypeIdentity { + public get identity(): MaybeTypeIdentity { return setOperationTypeIdentity(this.kind, this.getAttributes(), this.getMemberRefs()); } protected reconstituteSetOperation( builder: TypeReconstituter, canonicalOrder: boolean, - getType: (members: ReadonlySet | undefined) => void, + getType: (members: ReadonlySet | undefined) => void ): void { const sortedMemberRefs = mapMap(this.sortedMembers.entries(), t => t.typeRef); const membersInOrder = canonicalOrder ? this.sortedMembers : this.members; @@ -817,25 +845,28 @@ export abstract class SetOperationType extends Type { } } - protected structuralEqualityStep ( + protected structuralEqualityStep( other: SetOperationType, conflateNumbers: boolean, - queue: (a: Type, b: Type) => boolean, + queue: (a: Type, b: Type) => boolean ): boolean { return setOperationCasesEqual(this.members, other.members, conflateNumbers, queue); } } export class IntersectionType extends SetOperationType { - constructor (typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { + public constructor(typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { super(typeRef, graph, "intersection", memberRefs); } - get isNullable (): boolean { + public get isNullable(): boolean { return panic("isNullable not implemented for IntersectionType"); } - reconstitute(builder: TypeReconstituter, canonicalOrder: boolean): void { + public reconstitute( + builder: TypeReconstituter, + canonicalOrder: boolean + ): void { this.reconstituteSetOperation(builder, canonicalOrder, members => { if (members === undefined) { builder.getUniqueIntersectionType(); @@ -847,31 +878,31 @@ export class IntersectionType extends SetOperationType { } export class UnionType extends SetOperationType { - constructor (typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { + public constructor(typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { super(typeRef, graph, "union", memberRefs); if (memberRefs !== undefined) { messageAssert(memberRefs.size > 0, "IRNoEmptyUnions", {}); } } - setMembers (memberRefs: ReadonlySet): void { + public setMembers(memberRefs: ReadonlySet): void { messageAssert(memberRefs.size > 0, "IRNoEmptyUnions", {}); super.setMembers(memberRefs); } - get stringTypeMembers (): ReadonlySet { + public get stringTypeMembers(): ReadonlySet { return setFilter(this.members, t => isPrimitiveStringTypeKind(t.kind) || t.kind === "enum"); } - findMember (kind: TypeKind): Type | undefined { + public findMember(kind: TypeKind): Type | undefined { return iterableFind(this.members, t => t.kind === kind); } - get isNullable (): boolean { + public get isNullable(): boolean { return this.findMember("null") !== undefined; } - get isCanonical (): boolean { + public get isCanonical(): boolean { const members = this.members; if (members.size <= 1) return false; const kinds = setMap(members, t => t.kind); @@ -889,7 +920,10 @@ export class UnionType extends SetOperationType { return true; } - reconstitute(builder: TypeReconstituter, canonicalOrder: boolean): void { + public reconstitute( + builder: TypeReconstituter, + canonicalOrder: boolean + ): void { this.reconstituteSetOperation(builder, canonicalOrder, members => { if (members === undefined) { builder.getUniqueUnionType(); diff --git a/packages/quicktype-core/src/TypeBuilder.ts b/packages/quicktype-core/src/TypeBuilder.ts index 55d521857..d9a8b17ef 100644 --- a/packages/quicktype-core/src/TypeBuilder.ts +++ b/packages/quicktype-core/src/TypeBuilder.ts @@ -8,7 +8,7 @@ import { areEqual, setUnionManyInto, definedMap, - withDefault, + withDefault } from "collection-utils"; import { @@ -18,7 +18,7 @@ import { type MaybeTypeIdentity, type TypeIdentity, type TransformedStringTypeKind, - type TypeKind, + type TypeKind } from "./Type"; import { PrimitiveType, @@ -38,40 +38,35 @@ import { unionTypeIdentity, intersectionTypeIdentity, isPrimitiveStringTypeKind, - transformedStringTypeKinds, + transformedStringTypeKinds } from "./Type"; -import { type TypeRef} from "./TypeGraph"; +import { type TypeRef } from "./TypeGraph"; import { TypeGraph, makeTypeRef, derefTypeRef, typeRefIndex, assertTypeRefGraph } from "./TypeGraph"; -import { - type TypeAttributes} from "./attributes/TypeAttributes"; -import { - combineTypeAttributes, - TypeAttributeKind, - emptyTypeAttributes, -} from "./attributes/TypeAttributes"; +import { type TypeAttributes } from "./attributes/TypeAttributes"; +import { combineTypeAttributes, TypeAttributeKind, emptyTypeAttributes } from "./attributes/TypeAttributes"; import { defined, assert, panic } from "./support/Support"; import { stringTypesTypeAttributeKind, StringTypes } from "./attributes/StringTypes"; // FIXME: Don't infer provenance. All original types should be present in // non-inferred form in the final graph. class ProvenanceTypeAttributeKind extends TypeAttributeKind> { - constructor () { + public constructor() { super("provenance"); } - appliesToTypeKind (_kind: TypeKind): boolean { + public appliesToTypeKind(_kind: TypeKind): boolean { return true; } - combine (arr: Array>): Set { + public combine(arr: Array>): Set { return setUnionManyInto(new Set(), arr); } - makeInferred (p: Set): Set { + public makeInferred(p: Set): Set { return p; } - stringify (p: Set): string { + public stringify(p: Set): string { return Array.from(p) .sort() .map(i => i.toString()) @@ -83,7 +78,7 @@ export const provenanceTypeAttributeKind: TypeAttributeKind> = new P export type StringTypeMapping = ReadonlyMap; -export function stringTypeMappingGet (stm: StringTypeMapping, kind: TransformedStringTypeKind): PrimitiveStringTypeKind { +export function stringTypeMappingGet(stm: StringTypeMapping, kind: TransformedStringTypeKind): PrimitiveStringTypeKind { const mapped = stm.get(kind); if (mapped === undefined) return "string"; return mapped; @@ -91,12 +86,12 @@ export function stringTypeMappingGet (stm: StringTypeMapping, kind: TransformedS let noStringTypeMapping: StringTypeMapping | undefined; -export function getNoStringTypeMapping (): StringTypeMapping { +export function getNoStringTypeMapping(): StringTypeMapping { if (noStringTypeMapping === undefined) { noStringTypeMapping = new Map( Array.from(transformedStringTypeKinds).map( - k => [k, k] as [TransformedStringTypeKind, PrimitiveStringTypeKind], - ), + k => [k, k] as [TransformedStringTypeKind, PrimitiveStringTypeKind] + ) ); } @@ -104,7 +99,7 @@ export function getNoStringTypeMapping (): StringTypeMapping { } export class TypeBuilder { - readonly typeGraph: TypeGraph; + public readonly typeGraph: TypeGraph; protected readonly topLevels: Map = new Map(); @@ -114,32 +109,32 @@ export class TypeBuilder { private _addedForwardingIntersection = false; - constructor ( + public constructor( typeGraphSerial: number, private readonly _stringTypeMapping: StringTypeMapping, - readonly canonicalOrder: boolean, + public readonly canonicalOrder: boolean, private readonly _allPropertiesOptional: boolean, private readonly _addProvenanceAttributes: boolean, - inheritsProvenanceAttributes: boolean, + inheritsProvenanceAttributes: boolean ) { assert( !_addProvenanceAttributes || !inheritsProvenanceAttributes, - "We can't both inherit as well as add provenance", + "We can't both inherit as well as add provenance" ); this.typeGraph = new TypeGraph(this, typeGraphSerial, _addProvenanceAttributes || inheritsProvenanceAttributes); } - addTopLevel (name: string, tref: TypeRef): void { + public addTopLevel(name: string, tref: TypeRef): void { // assert(t.typeGraph === this.typeGraph, "Adding top-level to wrong type graph"); assert(!this.topLevels.has(name), "Trying to add top-level with existing name"); assert( this.types[typeRefIndex(tref)] !== undefined, - "Trying to add a top-level type that doesn't exist (yet?)", + "Trying to add a top-level type that doesn't exist (yet?)" ); this.topLevels.set(name, tref); } - reserveTypeRef (): TypeRef { + public reserveTypeRef(): TypeRef { const index = this.types.length; // console.log(`reserving ${index}`); this.types.push(undefined); @@ -151,17 +146,17 @@ export class TypeBuilder { return tref; } - private assertTypeRefGraph (tref: TypeRef | undefined): void { + private assertTypeRefGraph(tref: TypeRef | undefined): void { if (tref === undefined) return; assertTypeRefGraph(tref, this.typeGraph); } - private assertTypeRefSetGraph (trefs: ReadonlySet | undefined): void { + private assertTypeRefSetGraph(trefs: ReadonlySet | undefined): void { if (trefs === undefined) return; trefs.forEach(tref => this.assertTypeRefGraph(tref)); } - private filterTypeAttributes (t: Type, attributes: TypeAttributes): TypeAttributes { + private filterTypeAttributes(t: Type, attributes: TypeAttributes): TypeAttributes { const filtered = mapFilter(attributes, (_, k) => k.appliesToTypeKind(t.kind)); if (attributes.size !== filtered.size) { this.setLostTypeAttributes(); @@ -170,7 +165,7 @@ export class TypeBuilder { return filtered; } - private commitType (tref: TypeRef, t: Type): void { + private commitType(tref: TypeRef, t: Type): void { this.assertTypeRefGraph(tref); const index = typeRefIndex(tref); // const name = names !== undefined ? ` ${names.combinedName}` : ""; @@ -183,7 +178,7 @@ export class TypeBuilder { protected addType( forwardingRef: TypeRef | undefined, creator: (tref: TypeRef) => T, - attributes: TypeAttributes | undefined, + attributes: TypeAttributes | undefined ): TypeRef { if (forwardingRef !== undefined) { this.assertTypeRefGraph(forwardingRef); @@ -201,7 +196,7 @@ export class TypeBuilder { return tref; } - typeAtIndex (index: number): Type { + public typeAtIndex(index: number): Type { const maybeType = this.types[index]; if (maybeType === undefined) { return panic("Trying to deref an undefined type in a type builder"); @@ -210,13 +205,13 @@ export class TypeBuilder { return maybeType; } - atIndex (index: number): [Type, TypeAttributes] { + public atIndex(index: number): [Type, TypeAttributes] { const t = this.typeAtIndex(index); const attribtues = this.typeAttributes[index]; return [t, attribtues]; } - addAttributes (tref: TypeRef, attributes: TypeAttributes): void { + public addAttributes(tref: TypeRef, attributes: TypeAttributes): void { this.assertTypeRefGraph(tref); const index = typeRefIndex(tref); const existingAttributes = this.typeAttributes[index]; @@ -227,7 +222,7 @@ export class TypeBuilder { if (existing === undefined) return false; return areEqual(existing, v); }), - "Can't add different identity type attributes to an existing type", + "Can't add different identity type attributes to an existing type" ); const maybeType = this.types[index]; if (maybeType !== undefined) { @@ -238,46 +233,46 @@ export class TypeBuilder { this.typeAttributes[index] = combineTypeAttributes("union", existingAttributes, nonIdentityAttributes); } - finish (): TypeGraph { + public finish(): TypeGraph { this.typeGraph.freeze(this.topLevels, this.types.map(defined), this.typeAttributes); return this.typeGraph; } - protected addForwardingIntersection (forwardingRef: TypeRef, tref: TypeRef): TypeRef { + protected addForwardingIntersection(forwardingRef: TypeRef, tref: TypeRef): TypeRef { this.assertTypeRefGraph(tref); this._addedForwardingIntersection = true; return this.addType(forwardingRef, tr => new IntersectionType(tr, this.typeGraph, new Set([tref])), undefined); } - protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: undefined): undefined; - protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: TypeRef): TypeRef; - protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined; - protected forwardIfNecessary (forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined { + protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: undefined): undefined; + protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: TypeRef): TypeRef; + protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined; + protected forwardIfNecessary(forwardingRef: TypeRef | undefined, tref: TypeRef | undefined): TypeRef | undefined { if (tref === undefined) return undefined; if (forwardingRef === undefined) return tref; return this.addForwardingIntersection(forwardingRef, tref); } - get didAddForwardingIntersection (): boolean { + public get didAddForwardingIntersection(): boolean { return this._addedForwardingIntersection; } private readonly _typeForIdentity: EqualityMap = new EqualityMap(); - private registerTypeForIdentity (identity: MaybeTypeIdentity, tref: TypeRef): void { + private registerTypeForIdentity(identity: MaybeTypeIdentity, tref: TypeRef): void { if (identity === undefined) return; this._typeForIdentity.set(identity, tref); } - protected makeIdentity (maker: () => MaybeTypeIdentity): MaybeTypeIdentity { + protected makeIdentity(maker: () => MaybeTypeIdentity): MaybeTypeIdentity { return maker(); } - private getOrAddType ( + private getOrAddType( identityMaker: () => MaybeTypeIdentity, creator: (tr: TypeRef) => Type, attributes: TypeAttributes | undefined, - forwardingRef: TypeRef | undefined, + forwardingRef: TypeRef | undefined ): TypeRef { const identity = this.makeIdentity(identityMaker); let maybeTypeRef: TypeRef | undefined; @@ -296,7 +291,7 @@ export class TypeBuilder { // asserts that no identity attributes are added later. this.addAttributes( result, - mapFilter(attributes, (_, k) => !k.inIdentity), + mapFilter(attributes, (_, k) => !k.inIdentity) ); } @@ -308,11 +303,15 @@ export class TypeBuilder { return tref; } - private registerType (t: Type): void { + private registerType(t: Type): void { this.registerTypeForIdentity(t.identity, t.typeRef); } - getPrimitiveType (kind: PrimitiveTypeKind, maybeAttributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { + public getPrimitiveType( + kind: PrimitiveTypeKind, + maybeAttributes?: TypeAttributes, + forwardingRef?: TypeRef + ): TypeRef { const attributes = withDefault(maybeAttributes, emptyTypeAttributes); // FIXME: Why do date/time types need a StringTypes attribute? // FIXME: Remove this from here and put it into flattenStrings @@ -329,21 +328,25 @@ export class TypeBuilder { () => primitiveTypeIdentity(kind, attributes), tr => new PrimitiveType(tr, this.typeGraph, kind), attributes, - forwardingRef, + forwardingRef ); } - getStringType (attributes: TypeAttributes, stringTypes: StringTypes | undefined, forwardingRef?: TypeRef): TypeRef { + public getStringType( + attributes: TypeAttributes, + stringTypes: StringTypes | undefined, + forwardingRef?: TypeRef + ): TypeRef { const existingStringTypes = mapFind(attributes, (_, k) => k === stringTypesTypeAttributeKind); assert( - stringTypes === undefined !== (existingStringTypes === undefined), - "Must instantiate string type with one enum case attribute", + (stringTypes === undefined) !== (existingStringTypes === undefined), + "Must instantiate string type with one enum case attribute" ); if (existingStringTypes === undefined) { attributes = combineTypeAttributes( "union", attributes, - stringTypesTypeAttributeKind.makeAttributes(defined(stringTypes)), + stringTypesTypeAttributeKind.makeAttributes(defined(stringTypes)) ); } @@ -351,28 +354,28 @@ export class TypeBuilder { () => primitiveTypeIdentity("string", attributes), tr => new PrimitiveType(tr, this.typeGraph, "string"), attributes, - forwardingRef, + forwardingRef ); } - getEnumType (attributes: TypeAttributes, cases: ReadonlySet, forwardingRef?: TypeRef): TypeRef { + public getEnumType(attributes: TypeAttributes, cases: ReadonlySet, forwardingRef?: TypeRef): TypeRef { return this.getOrAddType( () => enumTypeIdentity(attributes, cases), tr => new EnumType(tr, this.typeGraph, cases), attributes, - forwardingRef, + forwardingRef ); } - makeClassProperty (tref: TypeRef, isOptional: boolean): ClassProperty { + public makeClassProperty(tref: TypeRef, isOptional: boolean): ClassProperty { return new ClassProperty(tref, this.typeGraph, isOptional); } - getUniqueObjectType ( + public getUniqueObjectType( attributes: TypeAttributes, properties: ReadonlyMap | undefined, additionalProperties: TypeRef | undefined, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { this.assertTypeRefGraph(additionalProperties); @@ -380,29 +383,29 @@ export class TypeBuilder { return this.addType( forwardingRef, tref => new ObjectType(tref, this.typeGraph, "object", true, properties, additionalProperties), - attributes, + attributes ); } - getUniqueMapType (forwardingRef?: TypeRef): TypeRef { + public getUniqueMapType(forwardingRef?: TypeRef): TypeRef { return this.addType(forwardingRef, tr => new MapType(tr, this.typeGraph, undefined), undefined); } - getMapType (attributes: TypeAttributes, values: TypeRef, forwardingRef?: TypeRef): TypeRef { + public getMapType(attributes: TypeAttributes, values: TypeRef, forwardingRef?: TypeRef): TypeRef { this.assertTypeRefGraph(values); return this.getOrAddType( () => mapTypeIdentify(attributes, values), tr => new MapType(tr, this.typeGraph, values), attributes, - forwardingRef, + forwardingRef ); } - setObjectProperties ( + public setObjectProperties( ref: TypeRef, properties: ReadonlyMap, - additionalProperties: TypeRef | undefined, + additionalProperties: TypeRef | undefined ): void { this.assertTypeRefGraph(additionalProperties); @@ -415,22 +418,22 @@ export class TypeBuilder { this.registerType(type); } - getUniqueArrayType (forwardingRef?: TypeRef): TypeRef { + public getUniqueArrayType(forwardingRef?: TypeRef): TypeRef { return this.addType(forwardingRef, tr => new ArrayType(tr, this.typeGraph, undefined), undefined); } - getArrayType (attributes: TypeAttributes, items: TypeRef, forwardingRef?: TypeRef): TypeRef { + public getArrayType(attributes: TypeAttributes, items: TypeRef, forwardingRef?: TypeRef): TypeRef { this.assertTypeRefGraph(items); return this.getOrAddType( () => arrayTypeIdentity(attributes, items), tr => new ArrayType(tr, this.typeGraph, items), attributes, - forwardingRef, + forwardingRef ); } - setArrayItems (ref: TypeRef, items: TypeRef): void { + public setArrayItems(ref: TypeRef, items: TypeRef): void { this.assertTypeRefGraph(items); const type = derefTypeRef(ref, this.typeGraph); @@ -442,7 +445,9 @@ export class TypeBuilder { this.registerType(type); } - modifyPropertiesIfNecessary (properties: ReadonlyMap): ReadonlyMap { + public modifyPropertiesIfNecessary( + properties: ReadonlyMap + ): ReadonlyMap { properties.forEach(p => this.assertTypeRefGraph(p.typeRef)); if (this.canonicalOrder) { @@ -456,81 +461,85 @@ export class TypeBuilder { return properties; } - getClassType ( + public getClassType( attributes: TypeAttributes, properties: ReadonlyMap, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { properties = this.modifyPropertiesIfNecessary(properties); return this.getOrAddType( () => classTypeIdentity(attributes, properties), tr => new ClassType(tr, this.typeGraph, false, properties), attributes, - forwardingRef, + forwardingRef ); } // FIXME: Maybe just distinguish between this and `getClassType` // via a flag? That would make `ClassType.map` simpler. - getUniqueClassType ( + public getUniqueClassType( attributes: TypeAttributes, isFixed: boolean, properties: ReadonlyMap | undefined, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { properties = definedMap(properties, p => this.modifyPropertiesIfNecessary(p)); return this.addType( forwardingRef, tref => new ClassType(tref, this.typeGraph, isFixed, properties), - attributes, + attributes ); } - getUnionType (attributes: TypeAttributes, members: ReadonlySet, forwardingRef?: TypeRef): TypeRef { + public getUnionType(attributes: TypeAttributes, members: ReadonlySet, forwardingRef?: TypeRef): TypeRef { this.assertTypeRefSetGraph(members); return this.getOrAddType( () => unionTypeIdentity(attributes, members), tr => new UnionType(tr, this.typeGraph, members), attributes, - forwardingRef, + forwardingRef ); } // FIXME: why do we sometimes call this with defined members??? - getUniqueUnionType ( + public getUniqueUnionType( attributes: TypeAttributes, members: ReadonlySet | undefined, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { this.assertTypeRefSetGraph(members); return this.addType(forwardingRef, tref => new UnionType(tref, this.typeGraph, members), attributes); } - getIntersectionType (attributes: TypeAttributes, members: ReadonlySet, forwardingRef?: TypeRef): TypeRef { + public getIntersectionType( + attributes: TypeAttributes, + members: ReadonlySet, + forwardingRef?: TypeRef + ): TypeRef { this.assertTypeRefSetGraph(members); return this.getOrAddType( () => intersectionTypeIdentity(attributes, members), tr => new IntersectionType(tr, this.typeGraph, members), attributes, - forwardingRef, + forwardingRef ); } // FIXME: why do we sometimes call this with defined members??? - getUniqueIntersectionType ( + public getUniqueIntersectionType( attributes: TypeAttributes, members: ReadonlySet | undefined, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { this.assertTypeRefSetGraph(members); return this.addType(forwardingRef, tref => new IntersectionType(tref, this.typeGraph, members), attributes); } - setSetOperationMembers (ref: TypeRef, members: ReadonlySet): void { + public setSetOperationMembers(ref: TypeRef, members: ReadonlySet): void { this.assertTypeRefSetGraph(members); const type = derefTypeRef(ref, this.typeGraph); @@ -542,7 +551,7 @@ export class TypeBuilder { this.registerType(type); } - setLostTypeAttributes (): void { + public setLostTypeAttributes(): void { return; } } diff --git a/packages/quicktype-core/src/TypeGraph.ts b/packages/quicktype-core/src/TypeGraph.ts index 5ffa13a48..2e5ddb1c4 100644 --- a/packages/quicktype-core/src/TypeGraph.ts +++ b/packages/quicktype-core/src/TypeGraph.ts @@ -1,17 +1,17 @@ import { iterableFirst, setFilter, setUnionManyInto, setSubtract, mapMap, mapSome, setMap } from "collection-utils"; -import { type Type} from "./Type"; +import { type Type } from "./Type"; import { ClassType, UnionType, IntersectionType } from "./Type"; -import { type SeparatedNamedTypes} from "./TypeUtils"; +import { type SeparatedNamedTypes } from "./TypeUtils"; import { separateNamedTypes, isNamedType, combineTypeAttributesOfTypes } from "./TypeUtils"; import { defined, assert, panic, mustNotHappen } from "./support/Support"; -import { type TypeBuilder, type StringTypeMapping} from "./TypeBuilder"; +import { type TypeBuilder, type StringTypeMapping } from "./TypeBuilder"; import { getNoStringTypeMapping, provenanceTypeAttributeKind } from "./TypeBuilder"; import { type BaseGraphRewriteBuilder } from "./GraphRewriting"; import { GraphRewriteBuilder, GraphRemapBuilder } from "./GraphRewriting"; import { TypeNames, namesTypeAttributeKind } from "./attributes/TypeNames"; import { Graph } from "./Graph"; -import { type TypeAttributeKind, type TypeAttributes} from "./attributes/TypeAttributes"; +import { type TypeAttributeKind, type TypeAttributes } from "./attributes/TypeAttributes"; import { emptyTypeAttributes } from "./attributes/TypeAttributes"; import { messageError } from "./Messages"; @@ -22,49 +22,49 @@ const indexMask = (1 << indexBits) - 1; const serialBits = 31 - indexBits; const serialMask = (1 << serialBits) - 1; -export function isTypeRef (x: any): x is TypeRef { +export function isTypeRef(x: any): x is TypeRef { return typeof x === "number"; } -export function makeTypeRef (graph: TypeGraph, index: number): TypeRef { +export function makeTypeRef(graph: TypeGraph, index: number): TypeRef { assert(index <= indexMask, "Too many types in graph"); - return (graph.serial & serialMask) << indexBits | index; + return ((graph.serial & serialMask) << indexBits) | index; } -export function typeRefIndex (tref: TypeRef): number { +export function typeRefIndex(tref: TypeRef): number { return tref & indexMask; } -export function assertTypeRefGraph (tref: TypeRef, graph: TypeGraph): void { +export function assertTypeRefGraph(tref: TypeRef, graph: TypeGraph): void { assert( - (tref >> indexBits & serialMask) === (graph.serial & serialMask), - "Mixing the wrong type reference and graph", + ((tref >> indexBits) & serialMask) === (graph.serial & serialMask), + "Mixing the wrong type reference and graph" ); } -function getGraph (graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): TypeGraph { +function getGraph(graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): TypeGraph { if (graphOrBuilder instanceof TypeGraph) return graphOrBuilder; return graphOrBuilder.originalGraph; } -export function derefTypeRef (tref: TypeRef, graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): Type { +export function derefTypeRef(tref: TypeRef, graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): Type { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); return graph.typeAtIndex(typeRefIndex(tref)); } -export function attributesForTypeRef ( +export function attributesForTypeRef( tref: TypeRef, - graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder, + graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder ): TypeAttributes { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); return graph.atIndex(typeRefIndex(tref))[1]; } -export function typeAndAttributesForTypeRef ( +export function typeAndAttributesForTypeRef( tref: TypeRef, - graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder, + graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder ): [Type, TypeAttributes] { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); @@ -74,15 +74,18 @@ export function typeAndAttributesForTypeRef ( export class TypeAttributeStore { private readonly _topLevelValues: Map = new Map(); - constructor (private readonly _typeGraph: TypeGraph, private _values: Array) {} + public constructor( + private readonly _typeGraph: TypeGraph, + private _values: Array + ) {} - private getTypeIndex (t: Type): number { + private getTypeIndex(t: Type): number { const tref = t.typeRef; assertTypeRefGraph(tref, this._typeGraph); return typeRefIndex(tref); } - attributesForType (t: Type): TypeAttributes { + public attributesForType(t: Type): TypeAttributes { const index = this.getTypeIndex(t); const maybeAttributes = this._values[index]; if (maybeAttributes !== undefined) { @@ -92,7 +95,7 @@ export class TypeAttributeStore { return emptyTypeAttributes; } - attributesForTopLevel (name: string): TypeAttributes { + public attributesForTopLevel(name: string): TypeAttributes { const maybeAttributes = this._topLevelValues.get(name); if (maybeAttributes !== undefined) { return maybeAttributes; @@ -101,12 +104,12 @@ export class TypeAttributeStore { return emptyTypeAttributes; } - private setInMap(attributes: TypeAttributes, kind: TypeAttributeKind, value: T): TypeAttributes { + public setInMap(attributes: TypeAttributes, kind: TypeAttributeKind, value: T): TypeAttributes { // FIXME: This is potentially super slow return new Map(attributes).set(kind, value); } - set(kind: TypeAttributeKind, t: Type, value: T): void { + public set(kind: TypeAttributeKind, t: Type, value: T): void { const index = this.getTypeIndex(t); while (index >= this._values.length) { this._values.push(undefined); @@ -115,50 +118,50 @@ export class TypeAttributeStore { this._values[index] = this.setInMap(this.attributesForType(t), kind, value); } - setForTopLevel(kind: TypeAttributeKind, topLevelName: string, value: T): void { + public setForTopLevel(kind: TypeAttributeKind, topLevelName: string, value: T): void { this._topLevelValues.set(topLevelName, this.setInMap(this.attributesForTopLevel(topLevelName), kind, value)); } - private tryGetInMap(attributes: TypeAttributes, kind: TypeAttributeKind): T | undefined { + public tryGetInMap(attributes: TypeAttributes, kind: TypeAttributeKind): T | undefined { return attributes.get(kind); } - tryGet(kind: TypeAttributeKind, t: Type): T | undefined { + public tryGet(kind: TypeAttributeKind, t: Type): T | undefined { return this.tryGetInMap(this.attributesForType(t), kind); } - tryGetForTopLevel(kind: TypeAttributeKind, topLevelName: string): T | undefined { + public tryGetForTopLevel(kind: TypeAttributeKind, topLevelName: string): T | undefined { return this.tryGetInMap(this.attributesForTopLevel(topLevelName), kind); } } export class TypeAttributeStoreView { - constructor ( + public constructor( private readonly _attributeStore: TypeAttributeStore, - private readonly _definition: TypeAttributeKind, + private readonly _definition: TypeAttributeKind ) {} - set (t: Type, value: T): void { + public set(t: Type, value: T): void { this._attributeStore.set(this._definition, t, value); } - setForTopLevel (name: string, value: T): void { + public setForTopLevel(name: string, value: T): void { this._attributeStore.setForTopLevel(this._definition, name, value); } - tryGet (t: Type): T | undefined { + public tryGet(t: Type): T | undefined { return this._attributeStore.tryGet(this._definition, t); } - get (t: Type): T { + public get(t: Type): T { return defined(this.tryGet(t)); } - tryGetForTopLevel (name: string): T | undefined { + public tryGetForTopLevel(name: string): T | undefined { return this._attributeStore.tryGetForTopLevel(this._definition, name); } - getForTopLevel (name: string): T { + public getForTopLevel(name: string): T { return defined(this.tryGetForTopLevel(name)); } } @@ -178,26 +181,26 @@ export class TypeGraph { private _printOnRewrite = false; - constructor ( + public constructor( typeBuilder: TypeBuilder, - readonly serial: number, - private readonly _haveProvenanceAttributes: boolean, + public readonly serial: number, + private readonly _haveProvenanceAttributes: boolean ) { this._typeBuilder = typeBuilder; } - private get isFrozen (): boolean { + private get isFrozen(): boolean { return this._typeBuilder === undefined; } - get attributeStore (): TypeAttributeStore { + public get attributeStore(): TypeAttributeStore { return defined(this._attributeStore); } - freeze ( + public freeze( topLevels: ReadonlyMap, types: Type[], - typeAttributes: Array, + typeAttributes: Array ): void { assert(!this.isFrozen, "Tried to freeze TypeGraph a second time"); for (const t of types) { @@ -215,12 +218,12 @@ export class TypeGraph { this._topLevels = mapMap(topLevels, tref => derefTypeRef(tref, this)); } - get topLevels (): ReadonlyMap { + public get topLevels(): ReadonlyMap { assert(this.isFrozen, "Cannot get top-levels from a non-frozen graph"); return this._topLevels; } - typeAtIndex (index: number): Type { + public typeAtIndex(index: number): Type { if (this._typeBuilder !== undefined) { return this._typeBuilder.typeAtIndex(index); } @@ -228,7 +231,7 @@ export class TypeGraph { return defined(this._types)[index]; } - atIndex (index: number): [Type, TypeAttributes] { + public atIndex(index: number): [Type, TypeAttributes] { if (this._typeBuilder !== undefined) { return this._typeBuilder.atIndex(index); } @@ -237,11 +240,11 @@ export class TypeGraph { return [t, defined(this._attributeStore).attributesForType(t)]; } - private filterTypes (predicate: ((t: Type) => boolean) | undefined): ReadonlySet { + private filterTypes(predicate: ((t: Type) => boolean) | undefined): ReadonlySet { const seen = new Set(); let types: Type[] = []; - function addFromType (t: Type): void { + function addFromType(t: Type): void { if (seen.has(t)) return; seen.add(t); @@ -263,16 +266,16 @@ export class TypeGraph { return new Set(types); } - allNamedTypes (): ReadonlySet { + public allNamedTypes(): ReadonlySet { return this.filterTypes(isNamedType); } - allNamedTypesSeparated (): SeparatedNamedTypes { + public allNamedTypesSeparated(): SeparatedNamedTypes { const types = this.allNamedTypes(); return separateNamedTypes(types); } - private allProvenance (): ReadonlySet { + private allProvenance(): ReadonlySet { assert(this._haveProvenanceAttributes); const view = new TypeAttributeStoreView(this.attributeStore, provenanceTypeAttributeKind); @@ -286,11 +289,11 @@ export class TypeGraph { return result; } - setPrintOnRewrite (): void { + private setPrintOnRewrite(): void { this._printOnRewrite = true; } - private checkLostTypeAttributes (builder: BaseGraphRewriteBuilder, newGraph: TypeGraph): void { + private checkLostTypeAttributes(builder: BaseGraphRewriteBuilder, newGraph: TypeGraph): void { if (!this._haveProvenanceAttributes || builder.lostTypeAttributes) return; const oldProvenance = this.allProvenance(); @@ -302,7 +305,7 @@ export class TypeGraph { } } - private printRewrite (title: string): void { + private printRewrite(title: string): void { if (!this._printOnRewrite) return; console.log(`\n# ${title}`); @@ -314,14 +317,14 @@ export class TypeGraph { // That particular TypeBuilder will have to take as inputs types in the old // graph, but return types in the new graph. Recursive types must be handled // carefully. - rewrite( + public rewrite( title: string, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, replacementGroups: T[][], debugPrintReconstitution: boolean, replacer: (typesToReplace: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef) => TypeRef, - force = false, + force = false ): TypeGraph { this.printRewrite(title); @@ -334,7 +337,7 @@ export class TypeGraph { this._haveProvenanceAttributes, replacementGroups, debugPrintReconstitution, - replacer, + replacer ); const newGraph = builder.finish(); @@ -350,13 +353,13 @@ export class TypeGraph { return removeIndirectionIntersections(newGraph, stringTypeMapping, debugPrintReconstitution); } - remap ( + public remap( title: string, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, map: ReadonlyMap, debugPrintRemapping: boolean, - force = false, + force = false ): TypeGraph { this.printRewrite(title); @@ -368,7 +371,7 @@ export class TypeGraph { alphabetizeProperties, this._haveProvenanceAttributes, map, - debugPrintRemapping, + debugPrintRemapping ); const newGraph = builder.finish(); @@ -384,19 +387,19 @@ export class TypeGraph { return newGraph; } - garbageCollect (alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { + public garbageCollect(alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { const newGraph = this.remap( "GC", getNoStringTypeMapping(), alphabetizeProperties, new Map(), debugPrintReconstitution, - true, + true ); return newGraph; } - rewriteFixedPoint (alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { + public rewriteFixedPoint(alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { let graph: TypeGraph = this; for (;;) { const newGraph = this.rewrite( @@ -406,7 +409,7 @@ export class TypeGraph { [], debugPrintReconstitution, mustNotHappen, - true, + true ); if (graph.allTypesUnordered().size === newGraph.allTypesUnordered().size) { return graph; @@ -416,16 +419,16 @@ export class TypeGraph { } } - allTypesUnordered (): ReadonlySet { + public allTypesUnordered(): ReadonlySet { assert(this.isFrozen, "Tried to get all graph types before it was frozen"); return new Set(defined(this._types)); } - makeGraph (invertDirection: boolean, childrenOfType: (t: Type) => ReadonlySet): Graph { + public makeGraph(invertDirection: boolean, childrenOfType: (t: Type) => ReadonlySet): Graph { return new Graph(defined(this._types), invertDirection, childrenOfType); } - getParentsOfType (t: Type): Set { + public getParentsOfType(t: Type): Set { assertTypeRefGraph(t.typeRef, this); if (this._parents === undefined) { const parents = defined(this._types).map(_ => new Set()); @@ -442,7 +445,7 @@ export class TypeGraph { return this._parents[t.index]; } - printGraph (): void { + private printGraph(): void { const types = defined(this._types); for (let i = 0; i < types.length; i++) { const t = types[i]; @@ -453,7 +456,7 @@ export class TypeGraph { parts.push( `children ${Array.from(children) .map(c => c.index) - .join(",")}`, + .join(",")}` ); } @@ -469,10 +472,10 @@ export class TypeGraph { } } -export function noneToAny ( +export function noneToAny( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): TypeGraph { const noneTypes = setFilter(graph.allTypesUnordered(), t => t.kind === "none"); if (noneTypes.size === 0) { @@ -490,16 +493,16 @@ export function noneToAny ( const attributes = combineTypeAttributesOfTypes("union", types); const tref = builder.getPrimitiveType("any", attributes, forwardingRef); return tref; - }, + } ); } -export function optionalToNullable ( +export function optionalToNullable( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): TypeGraph { - function rewriteClass (c: ClassType, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { + function rewriteClass(c: ClassType, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { const properties = mapMap(c.getProperties(), (p, name) => { const t = p.type; let ref: TypeRef; @@ -515,7 +518,7 @@ export function optionalToNullable ( } const attributes = namesTypeAttributeKind.setDefaultInAttributes(t.getAttributes(), () => - TypeNames.make(new Set([name]), new Set(), true), + TypeNames.make(new Set([name]), new Set(), true) ); ref = builder.getUnionType(attributes, members); } @@ -531,7 +534,7 @@ export function optionalToNullable ( const classesWithOptional = setFilter( graph.allTypesUnordered(), - t => t instanceof ClassType && mapSome(t.getProperties(), p => p.isOptional), + t => t instanceof ClassType && mapSome(t.getProperties(), p => p.isOptional) ); const replacementGroups = Array.from(classesWithOptional).map(c => [c as ClassType]); if (classesWithOptional.size === 0) { @@ -548,14 +551,14 @@ export function optionalToNullable ( assert(setOfClass.size === 1); const c = defined(iterableFirst(setOfClass)); return rewriteClass(c, builder, forwardingRef); - }, + } ); } -export function removeIndirectionIntersections ( +export function removeIndirectionIntersections( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintRemapping: boolean, + debugPrintRemapping: boolean ): TypeGraph { const map: Array<[Type, Type]> = []; diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index f85767fef..7a39c450a 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -1,32 +1,14 @@ import { setFilter, setSortBy, iterableFirst, setUnion, EqualityMap } from "collection-utils"; import { defined, panic, assert, assertNever } from "./support/Support"; -import { - type TypeAttributes, - type CombinationKind, -} from "./attributes/TypeAttributes"; -import { - combineTypeAttributes, - emptyTypeAttributes, -} from "./attributes/TypeAttributes"; -import { - type Type, - type PrimitiveType, - type ClassProperty, - type SetOperationType} from "./Type"; -import { - ArrayType, - EnumType, - ObjectType, - MapType, - ClassType, - UnionType, - isPrimitiveStringTypeKind, -} from "./Type"; +import { type TypeAttributes, type CombinationKind } from "./attributes/TypeAttributes"; +import { combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +import { type Type, type PrimitiveType, type ClassProperty, type SetOperationType } from "./Type"; +import { ArrayType, EnumType, ObjectType, MapType, ClassType, UnionType, isPrimitiveStringTypeKind } from "./Type"; import { type StringTypes } from "./attributes/StringTypes"; import { stringTypesTypeAttributeKind } from "./attributes/StringTypes"; -export function assertIsObject (t: Type): ObjectType { +export function assertIsObject(t: Type): ObjectType { if (t instanceof ObjectType) { return t; } @@ -34,7 +16,7 @@ export function assertIsObject (t: Type): ObjectType { return panic("Supposed object type is not an object type"); } -export function assertIsClass (t: Type): ClassType { +export function assertIsClass(t: Type): ClassType { if (!(t instanceof ClassType)) { return panic("Supposed class type is not a class type"); } @@ -42,17 +24,17 @@ export function assertIsClass (t: Type): ClassType { return t; } -export function setOperationMembersRecursively ( +export function setOperationMembersRecursively( setOperation: T, combinationKind: CombinationKind | undefined ): [ReadonlySet, TypeAttributes]; -export function setOperationMembersRecursively ( +export function setOperationMembersRecursively( setOperations: T[], combinationKind: CombinationKind | undefined ): [ReadonlySet, TypeAttributes]; -export function setOperationMembersRecursively ( +export function setOperationMembersRecursively( oneOrMany: T | T[], - combinationKind: CombinationKind | undefined, + combinationKind: CombinationKind | undefined ): [ReadonlySet, TypeAttributes] { const setOperations = Array.isArray(oneOrMany) ? oneOrMany : [oneOrMany]; const kind = setOperations[0].kind; @@ -61,7 +43,7 @@ export function setOperationMembersRecursively ( const members = new Set(); let attributes = emptyTypeAttributes; - function process (t: Type): void { + function process(t: Type): void { if (t.kind === kind) { const so = t as T; if (processedSetOperations.has(so)) return; @@ -89,9 +71,9 @@ export function setOperationMembersRecursively ( return [members, attributes]; } -export function makeGroupsToFlatten ( +export function makeGroupsToFlatten( setOperations: Iterable, - include: ((members: ReadonlySet) => boolean) | undefined, + include: ((members: ReadonlySet) => boolean) | undefined ): Type[][] { const typeGroups = new EqualityMap, Set>(); for (const u of setOperations) { @@ -118,25 +100,25 @@ export function makeGroupsToFlatten ( return Array.from(typeGroups.values()).map(ts => Array.from(ts)); } -export function combineTypeAttributesOfTypes (combinationKind: CombinationKind, types: Iterable): TypeAttributes { +export function combineTypeAttributesOfTypes(combinationKind: CombinationKind, types: Iterable): TypeAttributes { return combineTypeAttributes( combinationKind, - Array.from(types).map(t => t.getAttributes()), + Array.from(types).map(t => t.getAttributes()) ); } -export function isAnyOrNull (t: Type): boolean { +export function isAnyOrNull(t: Type): boolean { return t.kind === "any" || t.kind === "null"; } // FIXME: We shouldn't have to sort here. This is just because we're not getting // back the right order from JSON Schema, due to the changes the intersection types // introduced. -export function removeNullFromUnion ( +export function removeNullFromUnion( t: UnionType, - sortBy: boolean | ((t: Type) => any) = false, + sortBy: boolean | ((t: Type) => any) = false ): [PrimitiveType | null, ReadonlySet] { - function sort (s: ReadonlySet): ReadonlySet { + function sort(s: ReadonlySet): ReadonlySet { if (sortBy === false) return s; if (sortBy === true) return setSortBy(s, m => m.kind); return setSortBy(s, sortBy); @@ -150,7 +132,7 @@ export function removeNullFromUnion ( return [nullType as PrimitiveType, sort(setFilter(t.members, m => m.kind !== "null"))]; } -export function removeNullFromType (t: Type): [PrimitiveType | null, ReadonlySet] { +export function removeNullFromType(t: Type): [PrimitiveType | null, ReadonlySet] { if (t.kind === "null") { return [t as PrimitiveType, new Set()]; } @@ -162,18 +144,18 @@ export function removeNullFromType (t: Type): [PrimitiveType | null, ReadonlySet return removeNullFromUnion(t); } -export function nullableFromUnion (t: UnionType): Type | null { +export function nullableFromUnion(t: UnionType): Type | null { const [hasNull, nonNulls] = removeNullFromUnion(t); if (hasNull === null) return null; if (nonNulls.size !== 1) return null; return defined(iterableFirst(nonNulls)); } -export function nonNullTypeCases (t: Type): ReadonlySet { +export function nonNullTypeCases(t: Type): ReadonlySet { return removeNullFromType(t)[1]; } -export function getNullAsOptional (cp: ClassProperty): [boolean, ReadonlySet] { +export function getNullAsOptional(cp: ClassProperty): [boolean, ReadonlySet] { const [maybeNull, nonNulls] = removeNullFromType(cp.type); if (cp.isOptional) { return [true, nonNulls]; @@ -184,7 +166,7 @@ export function getNullAsOptional (cp: ClassProperty): [boolean, ReadonlySet; } -export function separateNamedTypes (types: Iterable): SeparatedNamedTypes { +export function separateNamedTypes(types: Iterable): SeparatedNamedTypes { const objects = setFilter( types, - t => t.kind === "object" || t.kind === "class", + t => t.kind === "object" || t.kind === "class" ) as Set as ReadonlySet; const enums = setFilter(types, t => t instanceof EnumType) as Set as ReadonlySet; const unions = setFilter(types, t => t instanceof UnionType) as Set as ReadonlySet; @@ -205,17 +187,17 @@ export function separateNamedTypes (types: Iterable): SeparatedNamedTypes return { objects, enums, unions }; } -export function directlyReachableTypes (t: Type, setForType: (t: Type) => ReadonlySet | null): ReadonlySet { +export function directlyReachableTypes(t: Type, setForType: (t: Type) => ReadonlySet | null): ReadonlySet { const set = setForType(t); if (set !== null) return set; return setUnion(...Array.from(t.getNonAttributeChildren()).map(c => directlyReachableTypes(c, setForType))); } -export function directlyReachableSingleNamedType (type: Type): Type | undefined { +export function directlyReachableSingleNamedType(type: Type): Type | undefined { const definedTypes = directlyReachableTypes(type, t => { if ( - !(t instanceof UnionType) && isNamedType(t) || - t instanceof UnionType && nullableFromUnion(t) === null + (!(t instanceof UnionType) && isNamedType(t)) || + (t instanceof UnionType && nullableFromUnion(t) === null) ) { return new Set([t]); } @@ -226,7 +208,7 @@ export function directlyReachableSingleNamedType (type: Type): Type | undefined return iterableFirst(definedTypes); } -export function stringTypesForType (t: PrimitiveType): StringTypes { +export function stringTypesForType(t: PrimitiveType): StringTypes { assert(t.kind === "string", "Only strings can have string types"); const stringTypes = stringTypesTypeAttributeKind.tryGetInAttributes(t.getAttributes()); if (stringTypes === undefined) { @@ -242,7 +224,7 @@ export interface StringTypeMatchers { timeType?: (timeType: PrimitiveType) => U; } -export function matchTypeExhaustive ( +export function matchTypeExhaustive( t: Type, noneType: (noneType: PrimitiveType) => U, anyType: (anyType: PrimitiveType) => U, @@ -257,7 +239,7 @@ export function matchTypeExhaustive ( objectType: (objectType: ObjectType) => U, enumType: (enumType: EnumType) => U, unionType: (unionType: UnionType) => U, - transformedStringType: (transformedStringType: PrimitiveType) => U, + transformedStringType: (transformedStringType: PrimitiveType) => U ): U { if (t.isPrimitive()) { if (isPrimitiveStringTypeKind(t.kind)) { @@ -275,7 +257,7 @@ export function matchTypeExhaustive ( null: nullType, bool: boolType, integer: integerType, - double: doubleType, + double: doubleType }[kind]; if (f !== undefined) return f(t); return assertNever(f); @@ -288,7 +270,7 @@ export function matchTypeExhaustive ( return panic(`Unknown type ${t.kind}`); } -export function matchType ( +export function matchType( type: Type, anyType: (anyType: PrimitiveType) => U, nullType: (nullType: PrimitiveType) => U, @@ -301,9 +283,9 @@ export function matchType ( mapType: (mapType: MapType) => U, enumType: (enumType: EnumType) => U, unionType: (unionType: UnionType) => U, - transformedStringType?: (transformedStringType: PrimitiveType) => U, + transformedStringType?: (transformedStringType: PrimitiveType) => U ): U { - function typeNotSupported (t: Type) { + function typeNotSupported(t: Type) { return panic(`Unsupported type ${t.kind} in non-exhaustive match`); } @@ -322,19 +304,19 @@ export function matchType ( typeNotSupported, enumType, unionType, - transformedStringType || typeNotSupported, + transformedStringType || typeNotSupported ); } -export function matchCompoundType ( +export function matchCompoundType( t: Type, arrayType: (arrayType: ArrayType) => void, classType: (classType: ClassType) => void, mapType: (mapType: MapType) => void, objectType: (objectType: ObjectType) => void, - unionType: (unionType: UnionType) => void, + unionType: (unionType: UnionType) => void ): void { - function ignore (_: T): void { + function ignore(_: T): void { return; } @@ -353,6 +335,6 @@ export function matchCompoundType ( objectType, ignore, unionType, - ignore, + ignore ); } diff --git a/packages/quicktype-core/src/UnifyClasses.ts b/packages/quicktype-core/src/UnifyClasses.ts index b94bec7ad..dbf5fa4b2 100644 --- a/packages/quicktype-core/src/UnifyClasses.ts +++ b/packages/quicktype-core/src/UnifyClasses.ts @@ -7,15 +7,15 @@ import { type TypeBuilder } from "./TypeBuilder"; import { type TypeLookerUp, type GraphRewriteBuilder, type BaseGraphRewriteBuilder } from "./GraphRewriting"; import { UnionBuilder, TypeRefUnionAccumulator } from "./UnionBuilder"; import { panic, assert, defined } from "./support/Support"; -import { type TypeAttributes} from "./attributes/TypeAttributes"; +import { type TypeAttributes } from "./attributes/TypeAttributes"; import { combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; -import { type TypeRef} from "./TypeGraph"; +import { type TypeRef } from "./TypeGraph"; import { derefTypeRef } from "./TypeGraph"; -function getCliqueProperties ( +function getCliqueProperties( clique: ObjectType[], builder: TypeBuilder, - makePropertyType: (types: ReadonlySet) => TypeRef, + makePropertyType: (types: ReadonlySet) => TypeRef ): [ReadonlyMap, TypeRef | undefined, boolean] { let lostTypeAttributes = false; let propertyNames = new Set(); @@ -68,10 +68,10 @@ function getCliqueProperties ( return [unifiedProperties, unifiedAdditionalProperties, lostTypeAttributes]; } -function countProperties (clique: ObjectType[]): { - hasAdditionalProperties: boolean, - hasNonAnyAdditionalProperties: boolean, - hasProperties: boolean, +function countProperties(clique: ObjectType[]): { + hasAdditionalProperties: boolean; + hasNonAnyAdditionalProperties: boolean; + hasProperties: boolean; } { let hasProperties = false; let hasAdditionalProperties = false; @@ -94,25 +94,25 @@ function countProperties (clique: ObjectType[]): { } export class UnifyUnionBuilder extends UnionBuilder { - constructor ( + public constructor( typeBuilder: BaseGraphRewriteBuilder, private readonly _makeObjectTypes: boolean, private readonly _makeClassesFixed: boolean, - private readonly _unifyTypes: (typesToUnify: TypeRef[]) => TypeRef, + private readonly _unifyTypes: (typesToUnify: TypeRef[]) => TypeRef ) { super(typeBuilder); } - protected makeObject ( + protected makeObject( objectRefs: TypeRef[], typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined, + forwardingRef: TypeRef | undefined ): TypeRef { const maybeTypeRef = this.typeBuilder.lookupTypeRefs(objectRefs, forwardingRef); if (maybeTypeRef !== undefined) { assert( forwardingRef === undefined || maybeTypeRef === forwardingRef, - "The forwarding ref must be consumed", + "The forwarding ref must be consumed" ); this.typeBuilder.addAttributes(maybeTypeRef, typeAttributes); return maybeTypeRef; @@ -125,19 +125,19 @@ export class UnifyUnionBuilder extends UnionBuilder assertIsObject(derefTypeRef(r, this.typeBuilder))); const { hasProperties, hasAdditionalProperties, hasNonAnyAdditionalProperties } = countProperties(objectTypes); - if (!this._makeObjectTypes && (hasNonAnyAdditionalProperties || !hasProperties && hasAdditionalProperties)) { + if (!this._makeObjectTypes && (hasNonAnyAdditionalProperties || (!hasProperties && hasAdditionalProperties))) { const propertyTypes = new Set(); for (const o of objectTypes) { setUnionInto( propertyTypes, - Array.from(o.getProperties().values()).map(cp => cp.typeRef), + Array.from(o.getProperties().values()).map(cp => cp.typeRef) ); } const additionalPropertyTypes = new Set( objectTypes .filter(o => o.getAdditionalProperties() !== undefined) - .map(o => defined(o.getAdditionalProperties()).typeRef), + .map(o => defined(o.getAdditionalProperties()).typeRef) ); setUnionInto(propertyTypes, additionalPropertyTypes); return this.typeBuilder.getMapType(typeAttributes, this._unifyTypes(Array.from(propertyTypes))); @@ -148,7 +148,7 @@ export class UnifyUnionBuilder extends UnionBuilder { assert(types.size > 0, "Property has no type"); return this._unifyTypes(Array.from(types).map(t => t.typeRef)); - }, + } ); if (lostTypeAttributes) { this.typeBuilder.setLostTypeAttributes(); @@ -159,7 +159,7 @@ export class UnifyUnionBuilder extends UnionBuilder ( +export function unionBuilderForUnification( typeBuilder: GraphRewriteBuilder, makeObjectTypes: boolean, makeClassesFixed: boolean, - conflateNumbers: boolean, + conflateNumbers: boolean ): UnionBuilder { return new UnifyUnionBuilder(typeBuilder, makeObjectTypes, makeClassesFixed, trefs => unifyTypes( @@ -195,20 +195,20 @@ export function unionBuilderForUnification ( emptyTypeAttributes, typeBuilder, unionBuilderForUnification(typeBuilder, makeObjectTypes, makeClassesFixed, conflateNumbers), - conflateNumbers, - ), + conflateNumbers + ) ); } // typeAttributes must not be reconstituted yet. // FIXME: The UnionBuilder might end up not being used. -export function unifyTypes ( +export function unifyTypes( types: ReadonlySet, typeAttributes: TypeAttributes, typeBuilder: GraphRewriteBuilder, unionBuilder: UnionBuilder, conflateNumbers: boolean, - maybeForwardingRef?: TypeRef, + maybeForwardingRef?: TypeRef ): TypeRef { typeAttributes = typeBuilder.reconstituteTypeAttributes(typeAttributes); if (types.size === 0) { diff --git a/packages/quicktype-core/src/UnionBuilder.ts b/packages/quicktype-core/src/UnionBuilder.ts index e3840144a..0573b18b7 100644 --- a/packages/quicktype-core/src/UnionBuilder.ts +++ b/packages/quicktype-core/src/UnionBuilder.ts @@ -1,15 +1,14 @@ import { mapMerge, mapUpdateInto, mapMap, setUnionInto } from "collection-utils"; -import { type TypeKind, type PrimitiveStringTypeKind, type Type, type PrimitiveTypeKind} from "./Type"; +import { type TypeKind, type PrimitiveStringTypeKind, type Type, type PrimitiveTypeKind } from "./Type"; import { UnionType, isPrimitiveTypeKind } from "./Type"; import { matchTypeExhaustive } from "./TypeUtils"; -import { - type TypeAttributes} from "./attributes/TypeAttributes"; +import { type TypeAttributes } from "./attributes/TypeAttributes"; import { combineTypeAttributes, emptyTypeAttributes, makeTypeAttributesInferred, - increaseTypeAttributesDistance, + increaseTypeAttributesDistance } from "./attributes/TypeAttributes"; import { defined, assert, panic, assertNever } from "./support/Support"; import { type TypeBuilder } from "./TypeBuilder"; @@ -37,26 +36,26 @@ export type TypeAttributeMap = Map; type TypeAttributeMapBuilder = Map; -function addAttributes ( +function addAttributes( accumulatorAttributes: TypeAttributes | undefined, - newAttributes: TypeAttributes, + newAttributes: TypeAttributes ): TypeAttributes { if (accumulatorAttributes === undefined) return newAttributes; return combineTypeAttributes("union", accumulatorAttributes, newAttributes); } -function setAttributes ( +function setAttributes( attributeMap: TypeAttributeMap, kind: T, - newAttributes: TypeAttributes, + newAttributes: TypeAttributes ): void { attributeMap.set(kind, addAttributes(attributeMap.get(kind), newAttributes)); } -function addAttributesToBuilder ( +function addAttributesToBuilder( builder: TypeAttributeMapBuilder, kind: T, - newAttributes: TypeAttributes, + newAttributes: TypeAttributes ): void { let arr = builder.get(kind); if (arr === undefined) { @@ -67,11 +66,11 @@ function addAttributesToBuilder ( arr.push(newAttributes); } -function buildTypeAttributeMap (builder: TypeAttributeMapBuilder): TypeAttributeMap { +function buildTypeAttributeMap(builder: TypeAttributeMapBuilder): TypeAttributeMap { return mapMap(builder, arr => combineTypeAttributes("union", arr)); } -function moveAttributes (map: TypeAttributeMap, fromKind: T, toKind: T): void { +function moveAttributes(map: TypeAttributeMap, fromKind: T, toKind: T): void { const fromAttributes = defined(map.get(fromKind)); map.delete(fromKind); setAttributes(map, toKind, fromAttributes); @@ -82,40 +81,40 @@ export class UnionAccumulator implements UnionTypeProvider = new Map(); - readonly arrayData: TArray[] = []; + public readonly arrayData: TArray[] = []; - readonly objectData: TObject[] = []; + public readonly objectData: TObject[] = []; private readonly _enumCases: Set = new Set(); private _lostTypeAttributes = false; - constructor (private readonly _conflateNumbers: boolean) {} + public constructor(private readonly _conflateNumbers: boolean) {} - private have (kind: TypeKind): boolean { + private have(kind: TypeKind): boolean { return ( this._nonStringTypeAttributes.has(kind) || this._stringTypeAttributes.has(kind as PrimitiveStringTypeKind) ); } - addNone (_attributes: TypeAttributes): void { + public addNone(_attributes: TypeAttributes): void { // FIXME: Add them to all members? Or add them to the union, which means we'd have // to change getMemberKinds() to also return the attributes for the union itself, // or add a new method that does that. this._lostTypeAttributes = true; } - addAny (attributes: TypeAttributes): void { + public addAny(attributes: TypeAttributes): void { addAttributesToBuilder(this._nonStringTypeAttributes, "any", attributes); this._lostTypeAttributes = true; } - addPrimitive (kind: PrimitiveTypeKind, attributes: TypeAttributes): void { + public addPrimitive(kind: PrimitiveTypeKind, attributes: TypeAttributes): void { assert(kind !== "any", "any must be added with addAny"); addAttributesToBuilder(this._nonStringTypeAttributes, kind, attributes); } - protected addFullStringType (attributes: TypeAttributes, stringTypes: StringTypes | undefined): void { + protected addFullStringType(attributes: TypeAttributes, stringTypes: StringTypes | undefined): void { let stringTypesAttributes: TypeAttributes | undefined = undefined; if (stringTypes === undefined) { stringTypes = stringTypesTypeAttributeKind.tryGetInAttributes(attributes); @@ -132,7 +131,7 @@ export class UnionAccumulator implements UnionTypeProvider implements UnionTypeProvider implements UnionTypeProvider, attributes: TypeAttributes): void { + public addEnum(cases: ReadonlySet, attributes: TypeAttributes): void { const maybeStringAttributes = this._stringTypeAttributes.get("string"); if (maybeStringAttributes !== undefined) { addAttributesToBuilder(this._stringTypeAttributes, "string", attributes); @@ -179,24 +178,24 @@ export class UnionAccumulator implements UnionTypeProvider { + public get enumCases(): ReadonlySet { return this._enumCases; } - getMemberKinds (): TypeAttributeMap { + public getMemberKinds(): TypeAttributeMap { assert(!(this.have("enum") && this.have("string")), "We can't have both strings and enums in the same union"); let merged = mapMerge( buildTypeAttributeMap(this._nonStringTypeAttributes), - buildTypeAttributeMap(this._stringTypeAttributes), + buildTypeAttributeMap(this._stringTypeAttributes) ); if (merged.size === 0) { @@ -221,20 +220,20 @@ export class UnionAccumulator implements UnionTypeProvider): [ReadonlyMap, TypeAttributes] { +function attributesForTypes(types: Iterable): [ReadonlyMap, TypeAttributes] { // These two maps are the reverse of each other. unionsForType is all the unions // that are ancestors of that type, when going from one of the given types, only // following unions. @@ -246,7 +245,7 @@ function attributesForTypes (types: Iterable): [ReadonlyMap = new Set(); - function traverse (t: Type, path: UnionOrFaux[], isEquivalentToRoot: boolean): void { + function traverse(t: Type, path: UnionOrFaux[], isEquivalentToRoot: boolean): void { if (t instanceof UnionType) { unions.add(t); if (isEquivalentToRoot) { @@ -261,9 +260,9 @@ function attributesForTypes (types: Iterable): [ReadonlyMap s === undefined ? new Set(path) : setUnionInto(s, path)); + mapUpdateInto(unionsForType, t, s => (s === undefined ? new Set(path) : setUnionInto(s, path))); for (const u of path) { - mapUpdateInto(typesForUnion, u, s => s === undefined ? new Set([t]) : s.add(t)); + mapUpdateInto(typesForUnion, u, s => (s === undefined ? new Set([t]) : s.add(t))); } } } @@ -278,7 +277,7 @@ function attributesForTypes (types: Iterable): [ReadonlyMap defined(typesForUnion.get(u)).size === 1); assert( singleAncestors.every(u => defined(typesForUnion.get(u)).has(t)), - "We messed up bookkeeping", + "We messed up bookkeeping" ); const inheritedAttributes = singleAncestors.map(u => u.getAttributes()); return combineTypeAttributes("union", [t.getAttributes()].concat(inheritedAttributes)); @@ -303,7 +302,7 @@ function attributesForTypes (types: Iterable): [ReadonlyMap { // There is a method analogous to this in the IntersectionAccumulator. It might // make sense to find a common interface. - private addType (t: Type, attributes: TypeAttributes): void { + private addType(t: Type, attributes: TypeAttributes): void { matchTypeExhaustive( t, _noneType => this.addNone(attributes), @@ -325,11 +324,11 @@ export class TypeRefUnionAccumulator extends UnionAccumulator return panic("The unions should have been eliminated in attributesForTypesInUnion"); }, transformedStringType => - this.addStringType(transformedStringType.kind as PrimitiveStringTypeKind, attributes), + this.addStringType(transformedStringType.kind as PrimitiveStringTypeKind, attributes) ); } - addTypes (types: Iterable): TypeAttributes { + public addTypes(types: Iterable): TypeAttributes { const [attributesMap, unionAttributes] = attributesForTypes(types); for (const [t, attributes] of attributesMap) { this.addType(t, attributes); @@ -340,24 +339,24 @@ export class TypeRefUnionAccumulator extends UnionAccumulator } export abstract class UnionBuilder { - constructor (protected readonly typeBuilder: TBuilder) {} + public constructor(protected readonly typeBuilder: TBuilder) {} - protected abstract makeObject ( + protected abstract makeObject( objects: TObjectData, typeAttributes: TypeAttributes, forwardingRef: TypeRef | undefined ): TypeRef; - protected abstract makeArray ( + protected abstract makeArray( arrays: TArrayData, typeAttributes: TypeAttributes, forwardingRef: TypeRef | undefined ): TypeRef; - private makeTypeOfKind ( + private makeTypeOfKind( typeProvider: UnionTypeProvider, kind: TypeKind, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined, + forwardingRef: TypeRef | undefined ): TypeRef { switch (kind) { case "string": @@ -381,11 +380,11 @@ export abstract class UnionBuilder, unique: boolean, typeAttributes: TypeAttributes, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { const kinds = typeProvider.getMemberKinds(); @@ -402,7 +401,7 @@ export abstract class UnionBuilder; export type AccessorNames = Map; class AccessorNamesTypeAttributeKind extends TypeAttributeKind { - constructor () { + public constructor() { super("accessorNames"); } - makeInferred (_: AccessorNames): undefined { + public makeInferred(_: AccessorNames): undefined { return undefined; } } @@ -32,7 +32,7 @@ class AccessorNamesTypeAttributeKind extends TypeAttributeKind { export const accessorNamesTypeAttributeKind: TypeAttributeKind = new AccessorNamesTypeAttributeKind(); // Returns [name, isFixed]. -function getFromEntry (entry: AccessorEntry, language: string): [string, boolean] | undefined { +function getFromEntry(entry: AccessorEntry, language: string): [string, boolean] | undefined { if (typeof entry === "string") return [entry, false]; const maybeForLanguage = entry.get(language); @@ -44,28 +44,28 @@ function getFromEntry (entry: AccessorEntry, language: string): [string, boolean return undefined; } -export function lookupKey (accessors: AccessorNames, key: string, language: string): [string, boolean] | undefined { +export function lookupKey(accessors: AccessorNames, key: string, language: string): [string, boolean] | undefined { const entry = accessors.get(key); if (entry === undefined) return undefined; return getFromEntry(entry, language); } -export function objectPropertyNames (o: ObjectType, language: string): Map { +export function objectPropertyNames(o: ObjectType, language: string): Map { const accessors = accessorNamesTypeAttributeKind.tryGetInAttributes(o.getAttributes()); const map = o.getProperties(); if (accessors === undefined) return mapMap(map, _ => undefined); return mapMap(map, (_cp, n) => lookupKey(accessors, n, language)); } -export function enumCaseNames (e: EnumType, language: string): Map { +export function enumCaseNames(e: EnumType, language: string): Map { const accessors = accessorNamesTypeAttributeKind.tryGetInAttributes(e.getAttributes()); if (accessors === undefined) return mapMap(e.cases.entries(), _ => undefined); return mapMap(e.cases.entries(), c => lookupKey(accessors, c, language)); } -export function getAccessorName ( +export function getAccessorName( names: Map, - original: string, + original: string ): [string | undefined, boolean] { const maybeName = names.get(original); if (maybeName === undefined) return [undefined, false]; @@ -80,15 +80,15 @@ export function getAccessorName ( // up its union's identifier(s), and then look up the member's accessor entries for that // identifier. Of course we might find more than one, potentially conflicting. class UnionIdentifierTypeAttributeKind extends TypeAttributeKind> { - constructor () { + public constructor() { super("unionIdentifier"); } - combine (arr: Array>): ReadonlySet { + public combine(arr: Array>): ReadonlySet { return setUnionManyInto(new Set(), arr); } - makeInferred (_: ReadonlySet): ReadonlySet { + public makeInferred(_: ReadonlySet): ReadonlySet { return new Set(); } } @@ -98,18 +98,18 @@ export const unionIdentifierTypeAttributeKind: TypeAttributeKind> { - constructor () { + public constructor() { super("unionMemberNames"); } - combine (arr: Array>): Map { + public combine(arr: Array>): Map { const result = new Map(); for (const m of arr) { mapMergeInto(result, m); @@ -122,13 +122,13 @@ class UnionMemberNamesTypeAttributeKind extends TypeAttributeKind> = new UnionMemberNamesTypeAttributeKind(); -export function makeUnionMemberNamesAttribute (unionAttributes: TypeAttributes, entry: AccessorEntry): TypeAttributes { +export function makeUnionMemberNamesAttribute(unionAttributes: TypeAttributes, entry: AccessorEntry): TypeAttributes { const identifiers = defined(unionIdentifierTypeAttributeKind.tryGetInAttributes(unionAttributes)); const map = mapFromIterable(identifiers, _ => entry); return unionMemberNamesTypeAttributeKind.makeAttributes(map); } -export function unionMemberName (u: UnionType, member: Type, language: string): [string | undefined, boolean] { +export function unionMemberName(u: UnionType, member: Type, language: string): [string | undefined, boolean] { const identifiers = unionIdentifierTypeAttributeKind.tryGetInAttributes(u.getAttributes()); if (identifiers === undefined) return [undefined, false]; @@ -168,7 +168,7 @@ export function unionMemberName (u: UnionType, member: Type, language: string): return [first, isFixed]; } -function isAccessorEntry (x: any): x is string | { [language: string]: string, } { +function isAccessorEntry(x: any): x is string | { [language: string]: string } { if (typeof x === "string") { return true; } @@ -176,22 +176,22 @@ function isAccessorEntry (x: any): x is string | { [language: string]: string, } return isStringMap(x, (v: any): v is string => typeof v === "string"); } -function makeAccessorEntry (ae: string | { [language: string]: string, }): AccessorEntry { +function makeAccessorEntry(ae: string | { [language: string]: string }): AccessorEntry { if (typeof ae === "string") return ae; return mapFromObject(ae); } -export function makeAccessorNames (x: any): AccessorNames { +export function makeAccessorNames(x: any): AccessorNames { // FIXME: Do proper error reporting const stringMap = checkStringMap(x, isAccessorEntry); return mapMap(mapFromObject(stringMap), makeAccessorEntry); } -export function accessorNamesAttributeProducer ( +export function accessorNamesAttributeProducer( schema: JSONSchema, canonicalRef: Ref, _types: Set, - cases: JSONSchema[] | undefined, + cases: JSONSchema[] | undefined ): JSONSchemaAttributes | undefined { if (typeof schema !== "object") return undefined; const maybeAccessors = schema["qt-accessors"]; @@ -205,10 +205,10 @@ export function accessorNamesAttributeProducer ( const accessors = checkArray(maybeAccessors, isAccessorEntry); messageAssert(cases.length === accessors.length, "SchemaWrongAccessorEntryArrayLength", { operation: "oneOf", - ref: canonicalRef.push("oneOf"), + ref: canonicalRef.push("oneOf") }); const caseAttributes = accessors.map(accessor => - makeUnionMemberNamesAttribute(identifierAttribute, makeAccessorEntry(accessor)), + makeUnionMemberNamesAttribute(identifierAttribute, makeAccessorEntry(accessor)) ); return { forUnion: identifierAttribute, forCases: caseAttributes }; } diff --git a/packages/quicktype-core/src/attributes/Constraints.ts b/packages/quicktype-core/src/attributes/Constraints.ts index d63442f26..1bb66e2cf 100644 --- a/packages/quicktype-core/src/attributes/Constraints.ts +++ b/packages/quicktype-core/src/attributes/Constraints.ts @@ -10,7 +10,7 @@ import { type JSONSchema } from "../input/JSONSchemaStore"; // `areEqual`, `hashCodeOf`. export type MinMaxConstraint = [number | undefined, number | undefined]; -function checkMinMaxConstraint (minmax: MinMaxConstraint): MinMaxConstraint | undefined { +function checkMinMaxConstraint(minmax: MinMaxConstraint): MinMaxConstraint | undefined { const [min, max] = minmax; if (typeof min === "number" && typeof max === "number" && min > max) { return messageError("MiscInvalidMinMaxConstraint", { min, max }); @@ -24,20 +24,20 @@ function checkMinMaxConstraint (minmax: MinMaxConstraint): MinMaxConstraint | un } export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind { - constructor ( + public constructor( name: string, private readonly _typeKinds: Set, private _minSchemaProperty: string, - private _maxSchemaProperty: string, + private _maxSchemaProperty: string ) { super(name); } - get inIdentity (): boolean { + public get inIdentity(): boolean { return true; } - combine (arr: MinMaxConstraint[]): MinMaxConstraint | undefined { + public combine(arr: MinMaxConstraint[]): MinMaxConstraint | undefined { assert(arr.length > 0); let [min, max] = arr[0]; @@ -59,7 +59,7 @@ export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind 0); let [min, max] = arr[0]; @@ -81,11 +81,11 @@ export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind = new "minMax", new Set(["integer", "double"]), "minimum", - "maximum", + "maximum" ); export const minMaxLengthTypeAttributeKind: TypeAttributeKind = new MinMaxConstraintTypeAttributeKind( "minMaxLength", new Set(["string"]), "minLength", - "maxLength", + "maxLength" ); -function producer (schema: JSONSchema, minProperty: string, maxProperty: string): MinMaxConstraint | undefined { +function producer(schema: JSONSchema, minProperty: string, maxProperty: string): MinMaxConstraint | undefined { if (!(typeof schema === "object")) return undefined; let min: number | undefined = undefined; @@ -135,10 +135,10 @@ function producer (schema: JSONSchema, minProperty: string, maxProperty: string) return [min, max]; } -export function minMaxAttributeProducer ( +export function minMaxAttributeProducer( schema: JSONSchema, _ref: Ref, - types: Set, + types: Set ): JSONSchemaAttributes | undefined { if (!types.has("number") && !types.has("integer")) return undefined; @@ -147,10 +147,10 @@ export function minMaxAttributeProducer ( return { forNumber: minMaxTypeAttributeKind.makeAttributes(maybeMinMax) }; } -export function minMaxLengthAttributeProducer ( +export function minMaxLengthAttributeProducer( schema: JSONSchema, _ref: Ref, - types: Set, + types: Set ): JSONSchemaAttributes | undefined { if (!types.has("string")) return undefined; @@ -159,38 +159,38 @@ export function minMaxLengthAttributeProducer ( return { forString: minMaxLengthTypeAttributeKind.makeAttributes(maybeMinMaxLength) }; } -export function minMaxValueForType (t: Type): MinMaxConstraint | undefined { +export function minMaxValueForType(t: Type): MinMaxConstraint | undefined { return minMaxTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } -export function minMaxLengthForType (t: Type): MinMaxConstraint | undefined { +export function minMaxLengthForType(t: Type): MinMaxConstraint | undefined { return minMaxLengthTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } export class PatternTypeAttributeKind extends TypeAttributeKind { - constructor () { + public constructor() { super("pattern"); } - get inIdentity (): boolean { + public get inIdentity(): boolean { return true; } - combine (arr: string[]): string { + public combine(arr: string[]): string { assert(arr.length > 0); return arr.map(p => `(${p})`).join("|"); } - intersect (_arr: string[]): string | undefined { + public intersect(_arr: string[]): string | undefined { /** FIXME!!! what is the intersection of regexps? */ return undefined; } - makeInferred (_: string): undefined { + public makeInferred(_: string): undefined { return undefined; } - addToSchema (schema: { [name: string]: unknown, }, t: Type, attr: string): void { + public addToSchema(schema: { [name: string]: unknown }, t: Type, attr: string): void { if (t.kind !== "string") return; schema.pattern = attr; } @@ -198,10 +198,10 @@ export class PatternTypeAttributeKind extends TypeAttributeKind { export const patternTypeAttributeKind: TypeAttributeKind = new PatternTypeAttributeKind(); -export function patternAttributeProducer ( +export function patternAttributeProducer( schema: JSONSchema, _ref: Ref, - types: Set, + types: Set ): JSONSchemaAttributes | undefined { if (!(typeof schema === "object")) return undefined; if (!types.has("string")) return undefined; @@ -211,6 +211,6 @@ export function patternAttributeProducer ( return { forString: patternTypeAttributeKind.makeAttributes(patt) }; } -export function patternForType (t: Type): string | undefined { +export function patternForType(t: Type): string | undefined { return patternTypeAttributeKind.tryGetInAttributes(t.getAttributes()); } diff --git a/packages/quicktype-core/src/attributes/Description.ts b/packages/quicktype-core/src/attributes/Description.ts index 34bc6151c..9bf1d6588 100644 --- a/packages/quicktype-core/src/attributes/Description.ts +++ b/packages/quicktype-core/src/attributes/Description.ts @@ -5,7 +5,7 @@ import { iterableFirst, setUnionManyInto, mapMergeWithInto, - setSubtract, + setSubtract } from "collection-utils"; // There's a cyclic import here. Ignoring now because it requires a large refactor. @@ -17,32 +17,32 @@ import { PathElementKind } from "../input/JSONSchemaInput"; import { type JSONSchema } from "../input/JSONSchemaStore"; import { type Type } from "../Type"; -export function addDescriptionToSchema ( - schema: { [name: string]: unknown, }, - description: Iterable | undefined, +export function addDescriptionToSchema( + schema: { [name: string]: unknown }, + description: Iterable | undefined ): void { if (description === undefined) return; schema.description = Array.from(description).join("\n"); } class DescriptionTypeAttributeKind extends TypeAttributeKind> { - constructor () { + public constructor() { super("description"); } - combine (attrs: Array>): ReadonlySet { + public combine(attrs: Array>): ReadonlySet { return setUnionManyInto(new Set(), attrs); } - makeInferred (_: ReadonlySet): undefined { + public makeInferred(_: ReadonlySet): undefined { return undefined; } - addToSchema (schema: { [name: string]: unknown, }, _t: Type, attrs: ReadonlySet): void { + public addToSchema(schema: { [name: string]: unknown }, _t: Type, attrs: ReadonlySet): void { addDescriptionToSchema(schema, attrs); } - stringify (descriptions: ReadonlySet): string | undefined { + public stringify(descriptions: ReadonlySet): string | undefined { let result = iterableFirst(descriptions); if (result === undefined) return undefined; if (result.length > 5 + 3) { @@ -60,11 +60,11 @@ class DescriptionTypeAttributeKind extends TypeAttributeKind export const descriptionTypeAttributeKind: TypeAttributeKind> = new DescriptionTypeAttributeKind(); class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind>> { - constructor () { + public constructor() { super("propertyDescriptions"); } - combine (attrs: Array>>): Map> { + public combine(attrs: Array>>): Map> { // FIXME: Implement this with mutable sets const result = new Map>(); for (const attr of attrs) { @@ -74,11 +74,11 @@ class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind>): undefined { + public makeInferred(_: Map>): undefined { return undefined; } - stringify (propertyDescriptions: Map>): string | undefined { + public stringify(propertyDescriptions: Map>): string | undefined { if (propertyDescriptions.size === 0) return undefined; return `prop descs: ${propertyDescriptions.size}`; } @@ -87,14 +87,14 @@ class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind>> = new PropertyDescriptionsTypeAttributeKind(); -function isPropertiesKey (el: PathElement): boolean { +function isPropertiesKey(el: PathElement): boolean { return el.kind === PathElementKind.KeyOrIndex && el.key === "properties"; } -export function descriptionAttributeProducer ( +export function descriptionAttributeProducer( schema: JSONSchema, ref: Ref, - types: Set, + types: Set ): JSONSchemaAttributes | undefined { if (!(typeof schema === "object")) return undefined; diff --git a/packages/quicktype-core/src/attributes/EnumValues.ts b/packages/quicktype-core/src/attributes/EnumValues.ts index ccb3a6a24..38ac38542 100644 --- a/packages/quicktype-core/src/attributes/EnumValues.ts +++ b/packages/quicktype-core/src/attributes/EnumValues.ts @@ -1,6 +1,6 @@ import { mapMap } from "collection-utils"; -import { type AccessorNames} from "./AccessorNames"; +import { type AccessorNames } from "./AccessorNames"; import { lookupKey, makeAccessorNames } from "./AccessorNames"; import { type EnumType } from "../Type"; import { TypeAttributeKind } from "./TypeAttributes"; @@ -8,27 +8,27 @@ import { type JSONSchema } from "../input/JSONSchemaStore"; import { type Ref, type JSONSchemaType, type JSONSchemaAttributes } from "../input/JSONSchemaInput"; class EnumValuesTypeAttributeKind extends TypeAttributeKind { - constructor () { + public constructor() { super("enumValues"); } - makeInferred (_: AccessorNames) { + public makeInferred(_: AccessorNames) { return undefined; } } export const enumValuesTypeAttributeKind: TypeAttributeKind = new EnumValuesTypeAttributeKind(); -export function enumCaseValues (e: EnumType, language: string): Map { +export function enumCaseValues(e: EnumType, language: string): Map { const enumValues = enumValuesTypeAttributeKind.tryGetInAttributes(e.getAttributes()); if (enumValues === undefined) return mapMap(e.cases.entries(), _ => undefined); return mapMap(e.cases.entries(), c => lookupKey(enumValues, c, language)); } -export function enumValuesAttributeProducer ( +export function enumValuesAttributeProducer( schema: JSONSchema, _canonicalRef: Ref | undefined, - _types: Set, + _types: Set ): JSONSchemaAttributes | undefined { if (typeof schema !== "object") return undefined; diff --git a/packages/quicktype-core/src/attributes/StringTypes.ts b/packages/quicktype-core/src/attributes/StringTypes.ts index 555301d80..4c0083e82 100644 --- a/packages/quicktype-core/src/attributes/StringTypes.ts +++ b/packages/quicktype-core/src/attributes/StringTypes.ts @@ -7,27 +7,27 @@ import { mapMergeWithInto, definedMap, addHashCode, - setUnionInto, + setUnionInto } from "collection-utils"; import { TypeAttributeKind } from "./TypeAttributes"; import { defined, assert } from "../support/Support"; -import { type StringTypeMapping} from "../TypeBuilder"; +import { type StringTypeMapping } from "../TypeBuilder"; import { stringTypeMappingGet } from "../TypeBuilder"; import { type TransformedStringTypeKind } from "../Type"; import { type DateTimeRecognizer } from "../DateTime"; export class StringTypes { - static readonly unrestricted: StringTypes = new StringTypes(undefined, new Set()); + public static readonly unrestricted: StringTypes = new StringTypes(undefined, new Set()); - static fromCase (s: string, count: number): StringTypes { - const caseMap: { [name: string]: number, } = {}; + public static fromCase(s: string, count: number): StringTypes { + const caseMap: { [name: string]: number } = {}; caseMap[s] = count; return new StringTypes(new Map([[s, count] as [string, number]]), new Set()); } - static fromCases (cases: string[]): StringTypes { - const caseMap: { [name: string]: number, } = {}; + public static fromCases(cases: string[]): StringTypes { + const caseMap: { [name: string]: number } = {}; for (const s of cases) { caseMap[s] = 1; } @@ -36,20 +36,20 @@ export class StringTypes { } // undefined means no restrictions - constructor ( - readonly cases: ReadonlyMap | undefined, - readonly transformations: ReadonlySet, + public constructor( + public readonly cases: ReadonlyMap | undefined, + public readonly transformations: ReadonlySet ) { if (cases === undefined) { assert(transformations.size === 0, "We can't have an unrestricted string that also allows transformations"); } } - get isRestricted (): boolean { + public get isRestricted(): boolean { return this.cases !== undefined; } - union (othersArray: StringTypes[], startIndex: number): StringTypes { + public union(othersArray: StringTypes[], startIndex: number): StringTypes { if (this.cases === undefined) return this; const cases = new Map(this.cases); @@ -67,7 +67,7 @@ export class StringTypes { return new StringTypes(cases, transformations); } - intersect (othersArray: StringTypes[], startIndex: number): StringTypes { + public intersect(othersArray: StringTypes[], startIndex: number): StringTypes { let cases = this.cases; let transformations = this.transformations; @@ -95,7 +95,7 @@ export class StringTypes { return new StringTypes(cases, transformations); } - applyStringTypeMapping (mapping: StringTypeMapping): StringTypes { + public applyStringTypeMapping(mapping: StringTypeMapping): StringTypes { if (!this.isRestricted) return this; const kinds = new Set(); @@ -108,18 +108,18 @@ export class StringTypes { return new StringTypes(this.cases, new Set(kinds)); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof StringTypes)) return false; return areEqual(this.cases, other.cases) && areEqual(this.transformations, other.transformations); } - hashCode (): number { + public hashCode(): number { let h = hashCodeOf(this.cases); h = addHashCode(h, hashCodeOf(this.transformations)); return h; } - toString (): string { + public toString(): string { const parts: string[] = []; const enumCases = this.cases; @@ -139,33 +139,33 @@ export class StringTypes { } class StringTypesTypeAttributeKind extends TypeAttributeKind { - constructor () { + public constructor() { super("stringTypes"); } - get inIdentity (): boolean { + public get inIdentity(): boolean { return true; } - requiresUniqueIdentity (st: StringTypes): boolean { + public requiresUniqueIdentity(st: StringTypes): boolean { return st.cases !== undefined && st.cases.size > 0; } - combine (arr: StringTypes[]): StringTypes { + public combine(arr: StringTypes[]): StringTypes { assert(arr.length > 0); return arr[0].union(arr, 1); } - intersect (arr: StringTypes[]): StringTypes { + public intersect(arr: StringTypes[]): StringTypes { assert(arr.length > 0); return arr[0].intersect(arr, 1); } - makeInferred (_: StringTypes): undefined { + public makeInferred(_: StringTypes): undefined { return undefined; } - stringify (st: StringTypes): string { + public stringify(st: StringTypes): string { return st.toString(); } } @@ -178,7 +178,7 @@ const INTEGER_STRING = /^(0|-?[1-9]\d*)$/; const MIN_INTEGER_STRING = 1 << 31; const MAX_INTEGER_STRING = -(MIN_INTEGER_STRING + 1); -function isIntegerString (s: string): boolean { +function isIntegerString(s: string): boolean { if (INTEGER_STRING.exec(s) === null) { return false; } @@ -189,7 +189,7 @@ function isIntegerString (s: string): boolean { const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; -function isUUID (s: string): boolean { +function isUUID(s: string): boolean { return UUID.exec(s) !== null; } @@ -198,7 +198,7 @@ function isUUID (s: string): boolean { // with those characters which ajv refuses to accept as `uri`. const URI = /^(https?|ftp):\/\/[^{}]+$/; -function isURI (s: string): boolean { +function isURI(s: string): boolean { return URI.exec(s) !== null; } @@ -209,9 +209,9 @@ function isURI (s: string): boolean { * * @param s The string for which to determine the transformed string type kind. */ -export function inferTransformedStringTypeKindForString ( +export function inferTransformedStringTypeKindForString( s: string, - recognizer: DateTimeRecognizer, + recognizer: DateTimeRecognizer ): TransformedStringTypeKind | undefined { if (s.length === 0 || !"0123456789-abcdefth".includes(s[0])) return undefined; diff --git a/packages/quicktype-core/src/attributes/TypeAttributes.ts b/packages/quicktype-core/src/attributes/TypeAttributes.ts index 2077e0ca1..bf5a35d5b 100644 --- a/packages/quicktype-core/src/attributes/TypeAttributes.ts +++ b/packages/quicktype-core/src/attributes/TypeAttributes.ts @@ -5,67 +5,67 @@ import { type Type, type TypeKind } from "../Type"; import { type BaseGraphRewriteBuilder } from "../GraphRewriting"; export class TypeAttributeKind { - constructor (readonly name: string) {} + public constructor(public readonly name: string) {} - appliesToTypeKind (kind: TypeKind): boolean { + public appliesToTypeKind(kind: TypeKind): boolean { return kind !== "any"; } - combine (_attrs: T[]): T | undefined { + public combine(_attrs: T[]): T | undefined { return panic(`Cannot combine type attribute ${this.name}`); } - intersect (attrs: T[]): T | undefined { + public intersect(attrs: T[]): T | undefined { return this.combine(attrs); } - makeInferred (_: T): T | undefined { + public makeInferred(_: T): T | undefined { return panic(`Cannot make type attribute ${this.name} inferred`); } - increaseDistance (attrs: T): T | undefined { + public increaseDistance(attrs: T): T | undefined { return attrs; } - addToSchema (_schema: { [name: string]: unknown, }, _t: Type, _attrs: T): void { + public addToSchema(_schema: { [name: string]: unknown }, _t: Type, _attrs: T): void { return; } - children (_: T): ReadonlySet { + public children(_: T): ReadonlySet { return new Set(); } - stringify (_: T): string | undefined { + public stringify(_: T): string | undefined { return undefined; } - get inIdentity (): boolean { + public get inIdentity(): boolean { return false; } - requiresUniqueIdentity (_: T): boolean { + public requiresUniqueIdentity(_: T): boolean { return false; } - reconstitute(_builder: TBuilder, a: T): T { + public reconstitute(_builder: TBuilder, a: T): T { return a; } - makeAttributes (value: T): TypeAttributes { + public makeAttributes(value: T): TypeAttributes { const kvps: Array<[this, T]> = [[this, value]]; return new Map(kvps); } - tryGetInAttributes (a: TypeAttributes): T | undefined { + public tryGetInAttributes(a: TypeAttributes): T | undefined { return a.get(this); } - private setInAttributes (a: TypeAttributes, value: T): TypeAttributes { + private setInAttributes(a: TypeAttributes, value: T): TypeAttributes { // FIXME: This is potentially super slow return new Map(a).set(this, value); } - modifyInAttributes (a: TypeAttributes, modify: (value: T | undefined) => T | undefined): TypeAttributes { + public modifyInAttributes(a: TypeAttributes, modify: (value: T | undefined) => T | undefined): TypeAttributes { const modified = modify(this.tryGetInAttributes(a)); if (modified === undefined) { // FIXME: This is potentially super slow @@ -77,16 +77,16 @@ export class TypeAttributeKind { return this.setInAttributes(a, modified); } - setDefaultInAttributes (a: TypeAttributes, makeDefault: () => T): TypeAttributes { + public setDefaultInAttributes(a: TypeAttributes, makeDefault: () => T): TypeAttributes { if (this.tryGetInAttributes(a) !== undefined) return a; return this.modifyInAttributes(a, makeDefault); } - removeInAttributes (a: TypeAttributes): TypeAttributes { + public removeInAttributes(a: TypeAttributes): TypeAttributes { return mapFilter(a, (_, k) => k !== this); } - equals (other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof TypeAttributeKind)) { return false; } @@ -94,7 +94,7 @@ export class TypeAttributeKind { return this.name === other.name; } - hashCode (): number { + public hashCode(): number { return hashString(this.name); } } @@ -105,12 +105,12 @@ export const emptyTypeAttributes: TypeAttributes = new Map(); export type CombinationKind = "union" | "intersect"; -export function combineTypeAttributes (kind: CombinationKind, attributeArray: TypeAttributes[]): TypeAttributes; -export function combineTypeAttributes (kind: CombinationKind, a: TypeAttributes, b: TypeAttributes): TypeAttributes; -export function combineTypeAttributes ( +export function combineTypeAttributes(kind: CombinationKind, attributeArray: TypeAttributes[]): TypeAttributes; +export function combineTypeAttributes(kind: CombinationKind, a: TypeAttributes, b: TypeAttributes): TypeAttributes; +export function combineTypeAttributes( combinationKind: CombinationKind, firstOrArray: TypeAttributes[] | TypeAttributes, - second?: TypeAttributes, + second?: TypeAttributes ): TypeAttributes { const union = combinationKind === "union"; let attributeArray: TypeAttributes[]; @@ -126,7 +126,7 @@ export function combineTypeAttributes ( const attributesByKind = mapTranspose(attributeArray); - function combine (attrs: any[], kind: TypeAttributeKind): any { + function combine(attrs: any[], kind: TypeAttributeKind): any { assert(attrs.length > 0, "Cannot combine zero type attributes"); if (attrs.length === 1) return attrs[0]; if (union) { @@ -139,10 +139,10 @@ export function combineTypeAttributes ( return mapFilterMap(attributesByKind, combine); } -export function makeTypeAttributesInferred (attr: TypeAttributes): TypeAttributes { +export function makeTypeAttributesInferred(attr: TypeAttributes): TypeAttributes { return mapFilterMap(attr, (value, kind) => kind.makeInferred(value)); } -export function increaseTypeAttributesDistance (attr: TypeAttributes): TypeAttributes { +export function increaseTypeAttributesDistance(attr: TypeAttributes): TypeAttributes { return mapFilterMap(attr, (value, kind) => kind.increaseDistance(value)); } diff --git a/packages/quicktype-core/src/attributes/TypeNames.ts b/packages/quicktype-core/src/attributes/TypeNames.ts index 119ebec14..a1be97d07 100644 --- a/packages/quicktype-core/src/attributes/TypeNames.ts +++ b/packages/quicktype-core/src/attributes/TypeNames.ts @@ -10,14 +10,14 @@ import { Chance } from "../support/Chance"; let chance: Chance; let usedRandomNames: Set; -export function initTypeNames (): void { +export function initTypeNames(): void { chance = new Chance(31415); usedRandomNames = new Set(); } initTypeNames(); -function makeRandomName (): string { +function makeRandomName(): string { for (;;) { const name = `${chance.city()} ${chance.animal()}`; if (usedRandomNames.has(name)) continue; @@ -32,7 +32,7 @@ export type NameOrNames = string | TypeNames; // produce a name that includes the overlap twice. For example, for // the names "aaa" and "aaaa" we have the common prefix "aaa" and the // common suffix "aaa", so we will produce the combined name "aaaaaa". -function combineNames (names: ReadonlySet): string { +function combineNames(names: ReadonlySet): string { let originalFirst = iterableFirst(names); if (originalFirst === undefined) { return panic("Named type has no names"); @@ -45,7 +45,7 @@ function combineNames (names: ReadonlySet): string { const namesSet = setMap(names, s => splitIntoWords(s) .map(w => w.word.toLowerCase()) - .join("_"), + .join("_") ); const first = defined(iterableFirst(namesSet)); if (namesSet.size === 1) { @@ -85,10 +85,10 @@ function combineNames (names: ReadonlySet): string { export const tooManyNamesThreshold = 1000; export abstract class TypeNames { - static makeWithDistance ( + public static makeWithDistance( names: ReadonlySet, alternativeNames: ReadonlySet | undefined, - distance: number, + distance: number ): TypeNames { if (names.size >= tooManyNamesThreshold) { return new TooManyTypeNames(distance); @@ -101,41 +101,41 @@ export abstract class TypeNames { return new RegularTypeNames(names, alternativeNames, distance); } - static make ( + public static make( names: ReadonlySet, alternativeNames: ReadonlySet | undefined, - areInferred: boolean, + areInferred: boolean ): TypeNames { return TypeNames.makeWithDistance(names, alternativeNames, areInferred ? 1 : 0); } - constructor (readonly distance: number) {} + public constructor(public readonly distance: number) {} - get areInferred (): boolean { + public get areInferred(): boolean { return this.distance > 0; } - abstract get names (): ReadonlySet; - abstract get combinedName (): string; - abstract get proposedNames (): ReadonlySet; + public abstract get names(): ReadonlySet; + public abstract get combinedName(): string; + public abstract get proposedNames(): ReadonlySet; - abstract add (namesArray: TypeNames[], startIndex?: number): TypeNames; - abstract clearInferred (): TypeNames; - abstract makeInferred (): TypeNames; - abstract singularize (): TypeNames; - abstract toString (): string; + public abstract add(namesArray: TypeNames[], startIndex?: number): TypeNames; + public abstract clearInferred(): TypeNames; + public abstract makeInferred(): TypeNames; + public abstract singularize(): TypeNames; + public abstract toString(): string; } export class RegularTypeNames extends TypeNames { - constructor ( - readonly names: ReadonlySet, + public constructor( + public readonly names: ReadonlySet, private readonly _alternativeNames: ReadonlySet | undefined, - distance: number, + distance: number ) { super(distance); } - add (namesArray: TypeNames[], startIndex = 0): TypeNames { + public add(namesArray: TypeNames[], startIndex = 0): TypeNames { let newNames = new Set(this.names); let newDistance = this.distance; let newAlternativeNames = definedMap(this._alternativeNames, s => new Set(s)); @@ -174,16 +174,16 @@ export class RegularTypeNames extends TypeNames { return TypeNames.makeWithDistance(newNames, newAlternativeNames, newDistance); } - clearInferred (): TypeNames { + public clearInferred(): TypeNames { const newNames = this.areInferred ? new Set() : this.names; return TypeNames.makeWithDistance(newNames, new Set(), this.distance); } - get combinedName (): string { + public get combinedName(): string { return combineNames(this.names); } - get proposedNames (): ReadonlySet { + public get proposedNames(): ReadonlySet { const set = new Set([this.combinedName]); if (this._alternativeNames === undefined) { return set; @@ -193,19 +193,19 @@ export class RegularTypeNames extends TypeNames { return set; } - makeInferred (): TypeNames { + public makeInferred(): TypeNames { return TypeNames.makeWithDistance(this.names, this._alternativeNames, this.distance + 1); } - singularize (): TypeNames { + public singularize(): TypeNames { return TypeNames.makeWithDistance( setMap(this.names, pluralize.singular), definedMap(this._alternativeNames, an => setMap(an, pluralize.singular)), - this.distance + 1, + this.distance + 1 ); } - toString (): string { + public toString(): string { const inferred = this.areInferred ? `distance ${this.distance}` : "given"; const names = `${inferred} ${Array.from(this.names).join(",")}`; if (this._alternativeNames === undefined) { @@ -217,9 +217,9 @@ export class RegularTypeNames extends TypeNames { } export class TooManyTypeNames extends TypeNames { - readonly names: ReadonlySet; + public readonly names: ReadonlySet; - constructor (distance: number, name?: string) { + public constructor(distance: number, name?: string) { super(distance); if (name === undefined) { @@ -229,15 +229,15 @@ export class TooManyTypeNames extends TypeNames { this.names = new Set([name]); } - get combinedName (): string { + public get combinedName(): string { return defined(iterableFirst(this.names)); } - get proposedNames (): ReadonlySet { + public get proposedNames(): ReadonlySet { return this.names; } - add (namesArray: TypeNames[], startIndex = 0): TypeNames { + public add(namesArray: TypeNames[], startIndex = 0): TypeNames { if (!this.areInferred) return this; for (let i = startIndex; i < namesArray.length; i++) { @@ -250,7 +250,7 @@ export class TooManyTypeNames extends TypeNames { return this; } - clearInferred (): TypeNames { + public clearInferred(): TypeNames { if (!this.areInferred) { return this; } @@ -258,60 +258,60 @@ export class TooManyTypeNames extends TypeNames { return TypeNames.makeWithDistance(new Set(), new Set(), this.distance); } - makeInferred (): TypeNames { + public makeInferred(): TypeNames { return new TooManyTypeNames(this.distance + 1, iterableFirst(this.names)); } - singularize (): TypeNames { + public singularize(): TypeNames { return this; } - toString (): string { + public toString(): string { return `too many ${this.combinedName}`; } } class TypeNamesTypeAttributeKind extends TypeAttributeKind { - constructor () { + public constructor() { super("names"); } - combine (namesArray: TypeNames[]): TypeNames { + public combine(namesArray: TypeNames[]): TypeNames { assert(namesArray.length > 0, "Can't combine zero type names"); return namesArray[0].add(namesArray, 1); } - makeInferred (tn: TypeNames): TypeNames { + public makeInferred(tn: TypeNames): TypeNames { return tn.makeInferred(); } - increaseDistance (tn: TypeNames): TypeNames { + public increaseDistance(tn: TypeNames): TypeNames { return tn.makeInferred(); } - stringify (tn: TypeNames): string { + public stringify(tn: TypeNames): string { return tn.toString(); } } export const namesTypeAttributeKind: TypeAttributeKind = new TypeNamesTypeAttributeKind(); -export function modifyTypeNames ( +export function modifyTypeNames( attributes: TypeAttributes, - modifier: (tn: TypeNames | undefined) => TypeNames | undefined, + modifier: (tn: TypeNames | undefined) => TypeNames | undefined ): TypeAttributes { return namesTypeAttributeKind.modifyInAttributes(attributes, modifier); } -export function singularizeTypeNames (attributes: TypeAttributes): TypeAttributes { +export function singularizeTypeNames(attributes: TypeAttributes): TypeAttributes { return modifyTypeNames(attributes, maybeNames => { if (maybeNames === undefined) return undefined; return maybeNames.singularize(); }); } -export function makeNamesTypeAttributes (nameOrNames: NameOrNames, areNamesInferred?: boolean): TypeAttributes { +export function makeNamesTypeAttributes(nameOrNames: NameOrNames, areNamesInferred?: boolean): TypeAttributes { let typeNames: TypeNames; if (typeof nameOrNames === "string") { typeNames = TypeNames.make(new Set([nameOrNames]), new Set(), defined(areNamesInferred)); diff --git a/packages/quicktype-core/src/attributes/URIAttributes.ts b/packages/quicktype-core/src/attributes/URIAttributes.ts index 3213a389c..78e2fcc68 100644 --- a/packages/quicktype-core/src/attributes/URIAttributes.ts +++ b/packages/quicktype-core/src/attributes/URIAttributes.ts @@ -1,6 +1,6 @@ import URI from "urijs"; -import { type TypeAttributes} from "./TypeAttributes"; +import { type TypeAttributes } from "./TypeAttributes"; import { TypeAttributeKind, emptyTypeAttributes } from "./TypeAttributes"; import { setUnionManyInto } from "collection-utils"; import { type JSONSchemaType, type JSONSchemaAttributes, type Ref } from "../input/JSONSchemaInput"; @@ -15,25 +15,25 @@ const extensionsSchemaProperty = "qt-uri-extensions"; type URIAttributes = [ReadonlySet, ReadonlySet]; class URITypeAttributeKind extends TypeAttributeKind { - constructor () { + public constructor() { super("uriAttributes"); } - get inIdentity (): boolean { + public get inIdentity(): boolean { return true; } - combine (attrs: URIAttributes[]): URIAttributes { + public combine(attrs: URIAttributes[]): URIAttributes { const protocolSets = attrs.map(a => a[0]); const extensionSets = attrs.map(a => a[1]); return [setUnionManyInto(new Set(), protocolSets), setUnionManyInto(new Set(), extensionSets)]; } - makeInferred (_: URIAttributes): undefined { + public makeInferred(_: URIAttributes): undefined { return undefined; } - addToSchema (schema: { [name: string]: unknown, }, t: Type, attrs: URIAttributes): void { + public addToSchema(schema: { [name: string]: unknown }, t: Type, attrs: URIAttributes): void { if (t.kind !== "string" && t.kind !== "uri") return; const [protocols, extensions] = attrs; @@ -51,13 +51,13 @@ export const uriTypeAttributeKind: TypeAttributeKind = new URITyp const extensionRegex = /^.+(\.[^./\\]+)$/; -function pathExtension (path: string): string | undefined { +function pathExtension(path: string): string | undefined { const matches = extensionRegex.exec(path); if (matches === null) return undefined; return matches[1]; } -export function uriInferenceAttributesProducer (s: string): TypeAttributes { +export function uriInferenceAttributesProducer(s: string): TypeAttributes { try { const uri = URI(s); const extension = pathExtension(uri.path()); @@ -68,10 +68,10 @@ export function uriInferenceAttributesProducer (s: string): TypeAttributes { } } -export function uriSchemaAttributesProducer ( +export function uriSchemaAttributesProducer( schema: JSONSchema, _ref: Ref, - types: Set, + types: Set ): JSONSchemaAttributes | undefined { if (!(typeof schema === "object")) return undefined; if (!types.has("string")) return undefined; diff --git a/packages/quicktype-core/src/input/CompressedJSON.ts b/packages/quicktype-core/src/input/CompressedJSON.ts index 069834913..cb3909e0d 100644 --- a/packages/quicktype-core/src/input/CompressedJSON.ts +++ b/packages/quicktype-core/src/input/CompressedJSON.ts @@ -60,32 +60,32 @@ export abstract class CompressedJSON { private _arrays: Value[][] = []; - constructor( - readonly dateTimeRecognizer: DateTimeRecognizer, - readonly handleRefs: boolean + public constructor( + public readonly dateTimeRecognizer: DateTimeRecognizer, + public readonly handleRefs: boolean ) {} - abstract parse(input: T): Promise; + public abstract parse(input: T): Promise; - parseSync(_input: T): Value { + public parseSync(_input: T): Value { return panic("parseSync not implemented in CompressedJSON"); } - getStringForValue(v: Value): string { + public getStringForValue(v: Value): string { const tag = valueTag(v); assert(tag === Tag.InternedString || tag === Tag.TransformedString); return this._strings[getIndex(v, tag)]; } - getObjectForValue = (v: Value): Value[] => { + public getObjectForValue = (v: Value): Value[] => { return this._objects[getIndex(v, Tag.Object)]; }; - getArrayForValue = (v: Value): Value[] => { + public getArrayForValue = (v: Value): Value[] => { return this._arrays[getIndex(v, Tag.Array)]; }; - getStringFormatTypeKind(v: Value): TransformedStringTypeKind { + public getStringFormatTypeKind(v: Value): TransformedStringTypeKind { const kind = this._strings[getIndex(v, Tag.StringFormat)]; if (!isPrimitiveStringTypeKind(kind) || kind === "string") { return panic("Not a transformed string type kind"); @@ -252,11 +252,11 @@ export abstract class CompressedJSON { this._ctx = this._contextStack.pop(); } - equals(other: any): boolean { + public equals(other: any): boolean { return this === other; } - hashCode(): number { + public hashCode(): number { let hashAccumulator = hashCodeInit; for (const s of this._strings) { hashAccumulator = addHashCode(hashAccumulator, hashString(s)); @@ -284,11 +284,11 @@ export abstract class CompressedJSON { } export class CompressedJSONFromString extends CompressedJSON { - async parse(input: string): Promise { + public async parse(input: string): Promise { return this.parseSync(input); } - parseSync(input: string): Value { + public parseSync(input: string): Value { const json = JSON.parse(input); this.process(json); return this.finish(); diff --git a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts index 113baf372..edd9a8824 100644 --- a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts @@ -1,14 +1,14 @@ -import { type JSONSchema} from "./JSONSchemaStore"; +import { type JSONSchema } from "./JSONSchemaStore"; import { JSONSchemaStore } from "./JSONSchemaStore"; import { parseJSON } from ".."; import { readFromFileOrURL } from "./io/NodeIO"; export class FetchingJSONSchemaStore extends JSONSchemaStore { - constructor (private readonly _httpHeaders?: string[]) { + public constructor(private readonly _httpHeaders?: string[]) { super(); } - async fetch (address: string): Promise { + public async fetch(address: string): Promise { // console.log(`Fetching ${address}`); return parseJSON(await readFromFileOrURL(address, this._httpHeaders), "JSON Schema", address); } diff --git a/packages/quicktype-core/src/input/Inference.ts b/packages/quicktype-core/src/input/Inference.ts index 272c15d61..07c1c52d3 100644 --- a/packages/quicktype-core/src/input/Inference.ts +++ b/packages/quicktype-core/src/input/Inference.ts @@ -3,19 +3,12 @@ import { Tag, valueTag } from "./CompressedJSON"; import { assertNever, defined, panic, assert } from "../support/Support"; import { type TypeBuilder } from "../TypeBuilder"; import { UnionBuilder, UnionAccumulator } from "../UnionBuilder"; -import { - type ClassProperty} from "../Type"; -import { - transformedStringTypeTargetTypeKindsMap, - UnionType, - ClassType, - MapType, - ArrayType, -} from "../Type"; -import { type TypeAttributes} from "../attributes/TypeAttributes"; +import { type ClassProperty } from "../Type"; +import { transformedStringTypeTargetTypeKindsMap, UnionType, ClassType, MapType, ArrayType } from "../Type"; +import { type TypeAttributes } from "../attributes/TypeAttributes"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; import { StringTypes, inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; -import { type TypeRef} from "../TypeGraph"; +import { type TypeRef } from "../TypeGraph"; import { derefTypeRef } from "../TypeGraph"; import { messageError } from "../Messages"; import { nullableFromUnion } from "../TypeUtils"; @@ -23,9 +16,10 @@ import { nullableFromUnion } from "../TypeUtils"; // This should be the recursive type // Value[] | NestedValueArray[] // but TypeScript doesn't support that. -export type NestedValueArray = any; +// FIXME +export type NestedValueArray = Value[]; -function forEachArrayInNestedValueArray (va: NestedValueArray, f: (va: Value[]) => void): void { +function forEachArrayInNestedValueArray(va: NestedValueArray, f: (va: Value[]) => void): void { if (va.length === 0) { return; } @@ -39,7 +33,7 @@ function forEachArrayInNestedValueArray (va: NestedValueArray, f: (va: Value[]) } } -function forEachValueInNestedValueArray (va: NestedValueArray, f: (v: Value) => void): void { +function forEachValueInNestedValueArray(va: NestedValueArray, f: (v: Value) => void): void { forEachArrayInNestedValueArray(va, a => { for (const x of a) { f(x); @@ -48,35 +42,35 @@ function forEachValueInNestedValueArray (va: NestedValueArray, f: (v: Value) => } class InferenceUnionBuilder extends UnionBuilder { - constructor ( + public constructor( typeBuilder: TypeBuilder, private readonly _typeInference: TypeInference, - private readonly _fixed: boolean, + private readonly _fixed: boolean ) { super(typeBuilder); } - protected makeObject ( + protected makeObject( objects: NestedValueArray, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined, + forwardingRef: TypeRef | undefined ): TypeRef { return this._typeInference.inferClassType(typeAttributes, objects, this._fixed, forwardingRef); } - protected makeArray ( + protected makeArray( arrays: NestedValueArray, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined, + forwardingRef: TypeRef | undefined ): TypeRef { return this.typeBuilder.getArrayType( typeAttributes, - this._typeInference.inferType(emptyTypeAttributes, arrays, this._fixed, forwardingRef), + this._typeInference.inferType(emptyTypeAttributes, arrays, this._fixed, forwardingRef) ); } } -function canBeEnumCase (_s: string): boolean { +function canBeEnumCase(_s: string): boolean { return true; } @@ -85,14 +79,14 @@ export type Accumulator = UnionAccumulator; export class TypeInference { private _refIntersections: Array<[TypeRef, string[]]> | undefined; - constructor ( + public constructor( private readonly _cjson: CompressedJSON, private readonly _typeBuilder: TypeBuilder, private readonly _inferMaps: boolean, - private readonly _inferEnums: boolean, + private readonly _inferEnums: boolean ) {} - addValuesToAccumulator (valueArray: NestedValueArray, accumulator: Accumulator): void { + private addValuesToAccumulator(valueArray: NestedValueArray, accumulator: Accumulator): void { forEachValueInNestedValueArray(valueArray, value => { const t = valueTag(value); switch (t) { @@ -136,7 +130,7 @@ export class TypeInference { accumulator.addStringType( "string", emptyTypeAttributes, - new StringTypes(new Map(), new Set([kind])), + new StringTypes(new Map(), new Set([kind])) ); break; } @@ -163,17 +157,17 @@ export class TypeInference { }); } - inferType ( + public inferType( typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { const accumulator = this.accumulatorForArray(valueArray); return this.makeTypeFromAccumulator(accumulator, typeAttributes, fixed, forwardingRef); } - private resolveRef (ref: string, topLevel: TypeRef): TypeRef { + private resolveRef(ref: string, topLevel: TypeRef): TypeRef { if (!ref.startsWith("#/")) { return messageError("InferenceJSONReferenceNotRooted", { reference: ref }); } @@ -216,7 +210,7 @@ export class TypeInference { return tref; } - inferTopLevelType (typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean): TypeRef { + public inferTopLevelType(typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean): TypeRef { assert(this._refIntersections === undefined, "Didn't reset ref intersections - nested invocations?"); if (this._cjson.handleRefs) { this._refIntersections = []; @@ -235,30 +229,30 @@ export class TypeInference { return topLevel; } - accumulatorForArray (valueArray: NestedValueArray): Accumulator { + private accumulatorForArray(valueArray: NestedValueArray): Accumulator { const accumulator = new UnionAccumulator(true); this.addValuesToAccumulator(valueArray, accumulator); return accumulator; } - makeTypeFromAccumulator ( + private makeTypeFromAccumulator( accumulator: Accumulator, typeAttributes: TypeAttributes, fixed: boolean, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { const unionBuilder = new InferenceUnionBuilder(this._typeBuilder, this, fixed); return unionBuilder.buildUnion(accumulator, false, typeAttributes, forwardingRef); } - inferClassType ( + public inferClassType( typeAttributes: TypeAttributes, objects: NestedValueArray, fixed: boolean, - forwardingRef?: TypeRef, + forwardingRef?: TypeRef ): TypeRef { const propertyNames: string[] = []; - const propertyValues: { [name: string]: Value[], } = {}; + const propertyValues: { [name: string]: Value[] } = {}; forEachArrayInNestedValueArray(objects, arr => { for (let i = 0; i < arr.length; i += 2) { diff --git a/packages/quicktype-core/src/input/Inputs.ts b/packages/quicktype-core/src/input/Inputs.ts index 4d9ebc1de..5f57ac684 100644 --- a/packages/quicktype-core/src/input/Inputs.ts +++ b/packages/quicktype-core/src/input/Inputs.ts @@ -1,6 +1,6 @@ import { iterableFirst, iterableFind, iterableSome, setFilterMap, withDefault, arrayMapSync } from "collection-utils"; -import { type Value, type CompressedJSON} from "./CompressedJSON"; +import { type Value, type CompressedJSON } from "./CompressedJSON"; import { CompressedJSONFromString } from "./CompressedJSON"; import { panic, errorMessage, defined } from "../support/Support"; import { messageError } from "../Messages"; @@ -39,7 +39,8 @@ export interface Input { } interface JSONTopLevel { - description: string | undefined; samples: Value[]; + description: string | undefined; + samples: Value[]; } export interface JSONSourceData { @@ -48,26 +49,26 @@ export interface JSONSourceData { samples: T[]; } -function messageParseError (name: string, description: string | undefined, e: unknown): never { +function messageParseError(name: string, description: string | undefined, e: unknown): never { return messageError("MiscJSONParseError", { description: withDefault(description, "input"), address: name, - message: errorMessage(e), + message: errorMessage(e) }); } export class JSONInput implements Input> { - readonly kind: string = "json"; + public readonly kind: string = "json"; - readonly needIR: boolean = true; + public readonly needIR: boolean = true; - readonly needSchemaProcessing: boolean = false; + public readonly needSchemaProcessing: boolean = false; private readonly _topLevels: Map = new Map(); - constructor (private readonly _compressedJSON: CompressedJSON) {} + public constructor(private readonly _compressedJSON: CompressedJSON) {} - private addSample (topLevelName: string, sample: Value): void { + private addSample(topLevelName: string, sample: Value): void { let topLevel = this._topLevels.get(topLevelName); if (topLevel === undefined) { topLevel = { samples: [], description: undefined }; @@ -77,7 +78,7 @@ export class JSONInput implements Input> { topLevel.samples.push(sample); } - private setDescription (topLevelName: string, description: string): void { + private setDescription(topLevelName: string, description: string): void { let topLevel = this._topLevels.get(topLevelName); if (topLevel === undefined) { return panic("Trying to set description for a top-level that doesn't exist"); @@ -86,7 +87,7 @@ export class JSONInput implements Input> { topLevel.description = description; } - private addSamples (name: string, values: Value[], description: string | undefined): void { + private addSamples(name: string, values: Value[], description: string | undefined): void { for (const value of values) { this.addSample(name, value); if (description !== undefined) { @@ -95,7 +96,7 @@ export class JSONInput implements Input> { } } - async addSource (source: JSONSourceData): Promise { + public async addSource(source: JSONSourceData): Promise { const { name, samples, description } = source; try { const values = await arrayMapSync(samples, async s => await this._compressedJSON.parse(s)); @@ -105,7 +106,7 @@ export class JSONInput implements Input> { } } - addSourceSync (source: JSONSourceData): void { + public addSourceSync(source: JSONSourceData): void { const { name, samples, description } = source; try { const values = samples.map(s => this._compressedJSON.parseSync(s)); @@ -115,26 +116,26 @@ export class JSONInput implements Input> { } } - singleStringSchemaSource (): undefined { + public singleStringSchemaSource(): undefined { return undefined; } - async addTypes ( + public async addTypes( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean, + fixedTopLevels: boolean ): Promise { this.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); } - addTypesSync ( + public addTypesSync( _ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean, + fixedTopLevels: boolean ): void { const inference = new TypeInference(this._compressedJSON, typeBuilder, inferMaps, inferEnums); @@ -149,10 +150,10 @@ export class JSONInput implements Input> { } } -export function jsonInputForTargetLanguage ( +export function jsonInputForTargetLanguage( targetLanguage: string | TargetLanguage, languages?: TargetLanguage[], - handleJSONRefs = false, + handleJSONRefs = false ): JSONInput { if (typeof targetLanguage === "string") { targetLanguage = defined(languageNamed(targetLanguage, languages)); @@ -166,7 +167,7 @@ export class InputData { // FIXME: Make into a Map, indexed by kind. private _inputs: Set> = new Set(); - addInput(input: Input): void { + protected addInput(input: Input): void { this._inputs = this._inputs.add(input); } @@ -180,49 +181,49 @@ export class InputData { return input; } - async addSource(kind: string, source: T, makeInput: () => Input): Promise { + public async addSource(kind: string, source: T, makeInput: () => Input): Promise { const input = this.getOrAddInput(kind, makeInput); await input.addSource(source); } - addSourceSync(kind: string, source: T, makeInput: () => Input): void { + public addSourceSync(kind: string, source: T, makeInput: () => Input): void { const input = this.getOrAddInput(kind, makeInput); input.addSourceSync(source); } - async addTypes ( + public async addTypes( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean, + fixedTopLevels: boolean ): Promise { for (const input of this._inputs) { await input.addTypes(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); } } - addTypesSync ( + public addTypesSync( ctx: RunContext, typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean, + fixedTopLevels: boolean ): void { for (const input of this._inputs) { input.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); } } - get needIR (): boolean { + public get needIR(): boolean { return iterableSome(this._inputs, i => i.needIR); } - get needSchemaProcessing (): boolean { + public get needSchemaProcessing(): boolean { return iterableSome(this._inputs, i => i.needSchemaProcessing); } - singleStringSchemaSource (): string | undefined { + public singleStringSchemaSource(): string | undefined { const schemaStrings = setFilterMap(this._inputs, i => i.singleStringSchemaSource()); if (schemaStrings.size > 1) { return panic("We have more than one input with a string schema source"); diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index d3226c949..427e74d75 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -125,7 +125,7 @@ function normalizeURI(uri: string | URI): URI { } export class Ref { - static root(address: string | undefined): Ref { + public static root(address: string | undefined): Ref { const uri = definedMap(address, a => new URI(a)); return new Ref(uri, []); } @@ -146,7 +146,7 @@ export class Ref { return elements; } - static parseURI(uri: URI, destroyURI = false): Ref { + public static parseURI(uri: URI, destroyURI = false): Ref { if (!destroyURI) { uri = uri.clone(); } @@ -161,15 +161,15 @@ export class Ref { return new Ref(uri, elements); } - static parse(ref: string): Ref { + public static parse(ref: string): Ref { return Ref.parseURI(new URI(ref), true); } public addressURI: URI | undefined; - constructor( + public constructor( addressURI: URI | undefined, - readonly path: readonly PathElement[] + public readonly path: readonly PathElement[] ) { if (addressURI !== undefined) { assert(addressURI.fragment() === "", `Ref URI with fragment is not allowed: ${addressURI.toString()}`); @@ -179,15 +179,15 @@ export class Ref { } } - get hasAddress(): boolean { + public get hasAddress(): boolean { return this.addressURI !== undefined; } - get address(): string { + public get address(): string { return defined(this.addressURI).toString(); } - get isRoot(): boolean { + public get isRoot(): boolean { return this.path.length === 1 && this.path[0].kind === PathElementKind.Root; } @@ -197,7 +197,7 @@ export class Ref { return new Ref(this.addressURI, newPath); } - push(...keys: string[]): Ref { + public push(...keys: string[]): Ref { let ref: Ref = this; for (const key of keys) { ref = ref.pushElement({ kind: PathElementKind.KeyOrIndex, key }); @@ -206,15 +206,15 @@ export class Ref { return ref; } - pushObject(): Ref { + public pushObject(): Ref { return this.pushElement({ kind: PathElementKind.Object }); } - pushType(index: number): Ref { + public pushType(index: number): Ref { return this.pushElement({ kind: PathElementKind.Type, index }); } - resolveAgainst(base: Ref | undefined): Ref { + public resolveAgainst(base: Ref | undefined): Ref { let addressURI = this.addressURI; if (base?.addressURI !== undefined) { addressURI = addressURI === undefined ? base.addressURI : addressURI.absoluteTo(base.addressURI); @@ -223,7 +223,7 @@ export class Ref { return new Ref(addressURI, this.path); } - get name(): string { + public get name(): string { const path = Array.from(this.path); for (;;) { @@ -258,14 +258,14 @@ export class Ref { } } - get definitionName(): string | undefined { + public get definitionName(): string | undefined { const pe = arrayGetFromEnd(this.path, 2); if (pe === undefined) return undefined; if (keyOrIndex(pe) === "definitions") return keyOrIndex(defined(arrayLast(this.path))); return undefined; } - toString(): string { + public toString(): string { function elementToString(e: PathElement): string { switch (e.kind) { case PathElementKind.Root: @@ -326,11 +326,11 @@ export class Ref { } } - lookupRef(root: JSONSchema): JSONSchema { + public lookupRef(root: JSONSchema): JSONSchema { return this.lookup(root, this.path, root); } - equals(other: any): boolean { + public equals(other: any): boolean { if (!(other instanceof Ref)) return false; if (this.addressURI !== undefined && other.addressURI !== undefined) { if (!this.addressURI.equals(other.addressURI)) return false; @@ -347,7 +347,7 @@ export class Ref { return true; } - hashCode(): number { + public hashCode(): number { let acc = hashCodeOf(definedMap(this.addressURI, u => u.toString())); for (const pe of this.path) { acc = addHashCode(acc, pe.kind); @@ -372,16 +372,16 @@ class Location { public readonly virtualRef: Ref; - constructor( + public constructor( canonicalRef: Ref, virtualRef?: Ref, - readonly haveID: boolean = false + public readonly haveID: boolean = false ) { this.canonicalRef = canonicalRef; this.virtualRef = virtualRef !== undefined ? virtualRef : canonicalRef; } - updateWithID(id: any) { + public updateWithID(id: any) { if (typeof id !== "string") return this; const parsed = Ref.parse(id); const virtual = this.haveID ? parsed.resolveAgainst(this.virtualRef) : parsed; @@ -392,19 +392,19 @@ class Location { return new Location(this.canonicalRef, virtual, true); } - push(...keys: string[]): Location { + public push(...keys: string[]): Location { return new Location(this.canonicalRef.push(...keys), this.virtualRef.push(...keys), this.haveID); } - pushObject(): Location { + public pushObject(): Location { return new Location(this.canonicalRef.pushObject(), this.virtualRef.pushObject(), this.haveID); } - pushType(index: number): Location { + public pushType(index: number): Location { return new Location(this.canonicalRef.pushType(index), this.virtualRef.pushType(index), this.haveID); } - toString(): string { + public toString(): string { return `${this.virtualRef.toString()} (${this.canonicalRef.toString()})`; } } @@ -414,7 +414,7 @@ class Canonizer { private readonly _schemaAddressesAdded = new Set(); - constructor(private readonly _ctx: RunContext) {} + public constructor(private readonly _ctx: RunContext) {} private addIDs(schema: any, loc: Location) { if (schema === null) return; @@ -449,7 +449,7 @@ class Canonizer { } } - addSchema(schema: any, address: string): boolean { + public addSchema(schema: any, address: string): boolean { if (this._schemaAddressesAdded.has(address)) return false; this.addIDs(schema, new Location(Ref.root(address), Ref.root(undefined))); @@ -458,7 +458,7 @@ class Canonizer { } // Returns: Canonical ref - canonize(base: Location, ref: Ref): Location { + public canonize(base: Location, ref: Ref): Location { const virtual = ref.resolveAgainst(base.virtualRef); const loc = this._map.get(virtual); if (loc !== undefined) { @@ -560,7 +560,7 @@ function schemaFetchError(base: Location | undefined, address: string): never { } class Resolver { - constructor( + public constructor( private readonly _ctx: RunContext, private readonly _store: JSONSchemaStore, private readonly _canonizer: Canonizer @@ -608,7 +608,7 @@ class Resolver { } } - async resolveVirtualRef(base: Location, virtualRef: Ref): Promise<[JSONSchema, Location]> { + public async resolveVirtualRef(base: Location, virtualRef: Ref): Promise<[JSONSchema, Location]> { if (this._ctx.debugPrintSchemaResolving) { console.log(`resolving ${virtualRef.toString()} relative to ${base.toString()}`); } @@ -643,7 +643,7 @@ class Resolver { return schemaFetchError(base, virtualRef.address); } - async resolveTopLevelRef(ref: Ref): Promise<[JSONSchema, Location]> { + public async resolveTopLevelRef(ref: Ref): Promise<[JSONSchema, Location]> { return await this.resolveVirtualRef(new Location(new Ref(ref.addressURI, [])), new Ref(undefined, ref.path)); } } @@ -1151,14 +1151,14 @@ async function refsInSchemaForURI( } class InputJSONSchemaStore extends JSONSchemaStore { - constructor( + public constructor( private readonly _inputs: Map, private readonly _delegate?: JSONSchemaStore ) { super(); } - async fetch(address: string): Promise { + public async fetch(address: string): Promise { const maybeInput = this._inputs.get(address); if (maybeInput !== undefined) { return checkJSONSchema(parseJSON(maybeInput, "JSON Schema", address), () => Ref.root(address)); @@ -1180,9 +1180,9 @@ export interface JSONSchemaSourceData { } export class JSONSchemaInput implements Input { - readonly kind: string = "schema"; + public readonly kind: string = "schema"; - readonly needSchemaProcessing: boolean = true; + public readonly needSchemaProcessing: boolean = true; private readonly _attributeProducers: JSONSchemaAttributeProducer[]; @@ -1194,7 +1194,7 @@ export class JSONSchemaInput implements Input { private _needIR = false; - constructor( + public constructor( private _schemaStore: JSONSchemaStore | undefined, additionalAttributeProducers: JSONSchemaAttributeProducer[] = [], private readonly _additionalSchemaAddresses: readonly string[] = [] @@ -1210,15 +1210,15 @@ export class JSONSchemaInput implements Input { ].concat(additionalAttributeProducers); } - get needIR(): boolean { + public get needIR(): boolean { return this._needIR; } - addTopLevel(name: string, ref: Ref): void { + public addTopLevel(name: string, ref: Ref): void { this._topLevels.set(name, ref); } - async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise { + public async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise { if (this._schemaSources.length === 0) return; let maybeSchemaStore = this._schemaStore; @@ -1267,15 +1267,15 @@ export class JSONSchemaInput implements Input { await addTypesInSchema(resolver, typeBuilder, this._topLevels, this._attributeProducers); } - addTypesSync(): void { + public addTypesSync(): void { return panic("addTypesSync not supported in JSONSchemaInput"); } - async addSource(schemaSource: JSONSchemaSourceData): Promise { + public async addSource(schemaSource: JSONSchemaSourceData): Promise { this.addSourceSync(schemaSource); } - addSourceSync(schemaSource: JSONSchemaSourceData): void { + public addSourceSync(schemaSource: JSONSchemaSourceData): void { const { name, uris, schema, isConverted } = schemaSource; if (isConverted !== true) { @@ -1323,7 +1323,7 @@ export class JSONSchemaInput implements Input { } } - singleStringSchemaSource(): string | undefined { + public singleStringSchemaSource(): string | undefined { if (!this._schemaSources.every(([_, { schema }]) => typeof schema === "string")) { return undefined; } diff --git a/packages/quicktype-core/src/input/JSONSchemaStore.ts b/packages/quicktype-core/src/input/JSONSchemaStore.ts index 32f886e3e..9fe5c62ec 100644 --- a/packages/quicktype-core/src/input/JSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/JSONSchemaStore.ts @@ -1,4 +1,4 @@ -import { type StringMap} from "../support/Support"; +import { type StringMap } from "../support/Support"; import { assert } from "../support/Support"; export type JSONSchema = StringMap | boolean; @@ -6,15 +6,15 @@ export type JSONSchema = StringMap | boolean; export abstract class JSONSchemaStore { private readonly _schemas = new Map(); - private add (address: string, schema: JSONSchema): void { + private add(address: string, schema: JSONSchema): void { assert(!this._schemas.has(address), "Cannot set a schema for an address twice"); this._schemas.set(address, schema); } // FIXME: Remove the undefined option - abstract fetch (_address: string): Promise; + public abstract fetch(_address: string): Promise; - async get (address: string, debugPrint: boolean): Promise { + public async get(address: string, debugPrint: boolean): Promise { let schema = this._schemas.get(address); if (schema !== undefined) { return schema; diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index 96556fe3e..4bfb848ea 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -139,7 +139,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * @params names: names * @param extension: extension of files */ - constructor(displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { + public constructor(displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { super(displayName, names, extension); } @@ -164,7 +164,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Indicate if language support union with both number types * @return true */ - get supportsUnionsWithBothNumberTypes(): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } @@ -172,7 +172,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Indicate if language support optional class properties * @return true */ - get supportsOptionalClassProperties(): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } @@ -387,7 +387,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param renderContext: render context * @param _options: renderer options */ - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, private readonly _options: OptionValues diff --git a/packages/quicktype-core/src/language/CPlusPlus.ts b/packages/quicktype-core/src/language/CPlusPlus.ts index 94b60d3a4..f5ec4f5f0 100644 --- a/packages/quicktype-core/src/language/CPlusPlus.ts +++ b/packages/quicktype-core/src/language/CPlusPlus.ts @@ -125,7 +125,7 @@ export const cPlusPlusOptions = { }; export class CPlusPlusTargetLanguage extends TargetLanguage { - constructor(displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { + public constructor(displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { super(displayName, names, extension); } @@ -147,11 +147,11 @@ export class CPlusPlusTargetLanguage extends TargetLanguage { ]; } - get supportsUnionsWithBothNumberTypes(): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - get supportsOptionalClassProperties(): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } @@ -392,12 +392,12 @@ function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelik } class WrappingCode { - constructor( + public constructor( private readonly start: Sourcelike[], private readonly end: Sourcelike[] ) {} - wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { + public wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { return [addQualifier(qualifier, this.start), inner, this.end]; } } @@ -419,7 +419,7 @@ class BaseString { public _encodingFunction: Sourcelike; - constructor( + public constructor( stringType: string, constStringType: string, smatch: string, @@ -509,7 +509,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { protected readonly enumeratorNamingStyle: NamingStyle; - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, private readonly _options: OptionValues @@ -557,14 +557,14 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } // union typeguard - isUnion(t: Type | UnionType): t is UnionType { + private isUnion(t: Type | UnionType): t is UnionType { return t.kind === "union"; } // Returns true if the type can be stored in // a stack based optional type. This requires // that the type does not require forward declaration. - isOptionalAsValuePossible(t: Type): boolean { + private isOptionalAsValuePossible(t: Type): boolean { if (this.isForwardDeclaredType(t)) return false; if (this.isUnion(t)) { @@ -626,42 +626,42 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { return !this.isCycleBreakerType(t); } - isImplicitCycleBreaker(t: Type): boolean { + public isImplicitCycleBreaker(t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } // Is likely to return std::optional or boost::optional - optionalTypeStack(): string { + private optionalTypeStack(): string { return this._optionalType; } // Is likely to return std::make_optional or boost::optional - optionalFactoryStack(): string { + private optionalFactoryStack(): string { return this._optionalFactory; } // Is likely to return std::shared_ptr - optionalTypeHeap(): string { + private optionalTypeHeap(): string { return optionalAsSharedType; } // Is likely to return std::make_shared - optionalFactoryHeap(): string { + private optionalFactoryHeap(): string { return optionalFactoryAsSharedType; } // Returns the optional type most suitable for the given type. // Classes that don't require forward declarations can be stored // in std::optional ( or boost::optional ) - optionalType(t: Type): string { + private optionalType(t: Type): string { if (this.isOptionalAsValuePossible(t)) return this.optionalTypeStack(); else return this.optionalTypeHeap(); } // Returns a label that can be used to distinguish between // heap and stack based optional handling methods - optionalTypeLabel(t: Type): string { + private optionalTypeLabel(t: Type): string { if (this.isOptionalAsValuePossible(t)) return "stack"; else return "heap"; } @@ -3012,7 +3012,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } public NarrowString = new (class extends BaseString implements StringType { - constructor() { + public constructor() { super( "std::string", "const std::string & ", @@ -3040,7 +3040,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { })(); public WideString = new (class extends BaseString implements StringType { - constructor(public superThis: CPlusPlusRenderer) { + public constructor(public superThis: CPlusPlusRenderer) { super( "std::wstring", "const std::wstring & ", diff --git a/packages/quicktype-core/src/language/CSharp.ts b/packages/quicktype-core/src/language/CSharp.ts index e9ee7be51..f87193182 100644 --- a/packages/quicktype-core/src/language/CSharp.ts +++ b/packages/quicktype-core/src/language/CSharp.ts @@ -201,7 +201,7 @@ export const cSharpOptions = { }; export class CSharpTargetLanguage extends TargetLanguage { - constructor() { + public constructor() { super("C#", ["cs", "csharp"], "cs"); } @@ -222,7 +222,7 @@ export class CSharpTargetLanguage extends TargetLanguage { ]; } - get stringTypeMapping(): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date-time"); mapping.set("time", "date-time"); @@ -234,15 +234,15 @@ export class CSharpTargetLanguage extends TargetLanguage { return mapping; } - get supportsUnionsWithBothNumberTypes(): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - get supportsOptionalClassProperties(): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - needsTransformerForType(t: Type): boolean { + public needsTransformerForType(t: Type): boolean { const need = needTransformerForType(t); return need !== "none" && need !== "nullable"; } @@ -424,7 +424,7 @@ function isValueType(t: Type): boolean { } export class CSharpRenderer extends ConvenienceRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, private readonly _csOptions: OptionValues @@ -801,7 +801,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { private readonly _needNamespaces: boolean; - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, private readonly _options: OptionValues @@ -1562,7 +1562,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { private readonly _needNamespaces: boolean; - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, private readonly _options: OptionValues @@ -2428,19 +2428,19 @@ internal class IsoDateTimeOffsetConverter : JsonConverter public DateTimeStyles DateTimeStyles { - get => _dateTimeStyles; +public get => _dateTimeStyles; set => _dateTimeStyles = value; } public string? DateTimeFormat { - get => _dateTimeFormat ?? string.Empty; +public get => _dateTimeFormat ?? string.Empty; set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; } public CultureInfo Culture { - get => _culture ?? CultureInfo.CurrentCulture; +public get => _culture ?? CultureInfo.CurrentCulture; set => _culture = value; } diff --git a/packages/quicktype-core/src/language/Crystal.ts b/packages/quicktype-core/src/language/Crystal.ts index 61fcd28c9..05708f30a 100644 --- a/packages/quicktype-core/src/language/Crystal.ts +++ b/packages/quicktype-core/src/language/Crystal.ts @@ -13,32 +13,32 @@ import { escapeNonPrintableMapper, isPrintable, isAscii, - isLetterOrUnderscore, + isLetterOrUnderscore } from "../support/Strings"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { type UnionType, type Type, type ClassType, type EnumType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type Option } from "../RendererOptions"; import { type RenderContext } from "../Renderer"; export class CrystalTargetLanguage extends TargetLanguage { - protected makeRenderer (renderContext: RenderContext): CrystalRenderer { + protected makeRenderer(renderContext: RenderContext): CrystalRenderer { return new CrystalRenderer(this, renderContext); } - constructor () { + public constructor() { super("Crystal", ["crystal", "cr", "crystallang"], "cr"); } - protected get defaultIndentation (): string { + protected get defaultIndentation(): string { return " "; } - protected getOptions (): Array> { + protected getOptions(): Array> { return []; } } @@ -179,10 +179,10 @@ const keywords = [ "when", "while", "with", - "yield", + "yield" ]; -function isAsciiLetterOrUnderscoreOrDigit (codePoint: number): boolean { +function isAsciiLetterOrUnderscoreOrDigit(codePoint: number): boolean { if (!isAscii(codePoint)) { return false; } @@ -190,7 +190,7 @@ function isAsciiLetterOrUnderscoreOrDigit (codePoint: number): boolean { return isLetterOrUnderscoreOrDigit(codePoint); } -function isAsciiLetterOrUnderscore (codePoint: number): boolean { +function isAsciiLetterOrUnderscore(codePoint: number): boolean { if (!isAscii(codePoint)) { return false; } @@ -200,7 +200,7 @@ function isAsciiLetterOrUnderscore (codePoint: number): boolean { const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); -function crystalStyle (original: string, isSnakeCase: boolean): string { +function crystalStyle(original: string, isSnakeCase: boolean): string { const words = splitIntoWords(original); const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; @@ -213,7 +213,7 @@ function crystalStyle (original: string, isSnakeCase: boolean): string { wordStyle, wordStyle, isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore, + isAsciiLetterOrUnderscore ); return combined === "_" ? "_underscore" : combined; @@ -222,7 +222,7 @@ function crystalStyle (original: string, isSnakeCase: boolean): string { const snakeNamingFunction = funPrefixNamer("default", (original: string) => crystalStyle(original, true)); const camelNamingFunction = funPrefixNamer("camel", (original: string) => crystalStyle(original, false)); -function standardUnicodeCrystalEscape (codePoint: number): string { +function standardUnicodeCrystalEscape(codePoint: number): string { if (codePoint <= 0xffff) { return "\\u{" + intToHex(codePoint, 4) + "}"; } else { @@ -233,56 +233,56 @@ function standardUnicodeCrystalEscape (codePoint: number): string { const crystalStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeCrystalEscape)); export class CrystalRenderer extends ConvenienceRenderer { - constructor (targetLanguage: TargetLanguage, renderContext: RenderContext) { + public constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) { super(targetLanguage, renderContext); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return camelNamingFunction; } - protected namerForObjectProperty (): Namer | null { + protected namerForObjectProperty(): Namer | null { return snakeNamingFunction; } - protected makeUnionMemberNamer (): Namer | null { + protected makeUnionMemberNamer(): Namer | null { return camelNamingFunction; } - protected makeEnumCaseNamer (): Namer | null { + protected makeEnumCaseNamer(): Namer | null { return camelNamingFunction; } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected get commentLineStart (): string { + protected get commentLineStart(): string { return "# "; } - private nullableCrystalType (t: Type, withIssues: boolean): Sourcelike { + private nullableCrystalType(t: Type, withIssues: boolean): Sourcelike { return [this.crystalType(t, withIssues), "?"]; } - protected isImplicitCycleBreaker (t: Type): boolean { + protected isImplicitCycleBreaker(t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } - private crystalType (t: Type, withIssues = false): Sourcelike { + private crystalType(t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "JSON::Any?"), @@ -305,23 +305,23 @@ export class CrystalRenderer extends ConvenienceRenderer { const name = this.nameForNamedType(unionType); return hasNull !== null ? ([name, "?"] as Sourcelike) : name; - }, + } ); } - private breakCycle (t: Type, withIssues: boolean): Sourcelike { + private breakCycle(t: Type, withIssues: boolean): Sourcelike { return this.crystalType(t, withIssues); } - private emitRenameAttribute (propName: Name, jsonName: string): void { + private emitRenameAttribute(propName: Name, jsonName: string): void { const escapedName = crystalStringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; if (namesDiffer) { - this.emitLine("@[JSON::Field(key: \"", escapedName, "\")]"); + this.emitLine('@[JSON::Field(key: "', escapedName, '")]'); } } - protected emitStructDefinition (c: ClassType, className: Name): void { + protected emitStructDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); const structBody = () => @@ -335,7 +335,7 @@ export class CrystalRenderer extends ConvenienceRenderer { this.emitBlock(["class ", className], structBody); } - protected emitBlock (line: Sourcelike, f: () => void): void { + protected emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line); this.indent(() => { this.emitLine("include JSON::Serializable"); @@ -345,13 +345,13 @@ export class CrystalRenderer extends ConvenienceRenderer { this.emitLine("end"); } - protected emitEnum (line: Sourcelike, f: () => void): void { + protected emitEnum(line: Sourcelike, f: () => void): void { this.emitLine(line); this.indent(f); this.emitLine("end"); } - protected emitUnion (u: UnionType, unionName: Name): void { + protected emitUnion(u: UnionType, unionName: Name): void { const isMaybeWithSingleType = nullableFromUnion(u); if (isMaybeWithSingleType !== null) { @@ -372,30 +372,30 @@ export class CrystalRenderer extends ConvenienceRenderer { "alias ", unionName, " = ", - types.map(r => r.map(sl => this.sourcelikeToString(sl))).join(" | "), + types.map(r => r.map(sl => this.sourcelikeToString(sl))).join(" | ") ]); } - protected emitTopLevelAlias (t: Type, name: Name): void { + protected emitTopLevelAlias(t: Type, name: Name): void { this.emitLine("alias ", name, " = ", this.crystalType(t)); } - protected emitLeadingComments (): void { + protected emitLeadingComments(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); return; } } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.emitLeadingComments(); this.ensureBlankLine(); - this.emitLine("require \"json\""); + this.emitLine('require "json"'); this.forEachTopLevel( "leading", (t, name) => this.emitTopLevelAlias(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); this.forEachObject("leading-and-interposing", (c: ClassType, name: Name) => this.emitStructDefinition(c, name)); diff --git a/packages/quicktype-core/src/language/Dart.ts b/packages/quicktype-core/src/language/Dart.ts index 308d8091b..a30e797a1 100644 --- a/packages/quicktype-core/src/language/Dart.ts +++ b/packages/quicktype-core/src/language/Dart.ts @@ -4,11 +4,9 @@ import { type PrimitiveStringTypeKind, type TransformedStringTypeKind, type Type, - type UnionType, -} from "../Type"; -import { - EnumType, + type UnionType } from "../Type"; +import { EnumType } from "../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; import { type Sourcelike } from "../Source"; import { maybeAnnotated, modifySource } from "../Source"; @@ -27,7 +25,7 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters, + utf16LegalizeCharacters } from "../support/Strings"; import { type StringTypeMapping } from "../TypeBuilder"; @@ -37,7 +35,7 @@ import { DependencyName, funPrefixNamer } from "../Naming"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { BooleanOption, getOptionValues, StringOption } from "../RendererOptions"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { defined } from "../support/Support"; @@ -55,24 +53,24 @@ export const dartOptions = { "use-freezed", "Generate class definitions with @freezed compatibility", false, - "secondary", + "secondary" ), useHive: new BooleanOption("use-hive", "Generate annotations for Hive type adapters", false, "secondary"), useJsonAnnotation: new BooleanOption( "use-json-annotation", "Generate annotations for json_serializable", false, - "secondary", + "secondary" ), - partName: new StringOption("part-name", "Use this name in `part` directive", "NAME", "", "secondary"), + partName: new StringOption("part-name", "Use this name in `part` directive", "NAME", "", "secondary") }; export class DartTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Dart", ["dart"], "dart"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ dartOptions.nullSafety, dartOptions.justTypes, @@ -84,22 +82,22 @@ export class DartTargetLanguage extends TargetLanguage { dartOptions.useFreezed, dartOptions.useHive, dartOptions.useJsonAnnotation, - dartOptions.partName, + dartOptions.partName ]; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date"); mapping.set("date-time", "date-time"); return mapping; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): DartRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): DartRenderer { const options = getOptionValues(dartOptions, untypedOptionValues); return new DartRenderer(this, renderContext, options); } @@ -174,7 +172,7 @@ const keywords = [ "fromJson", "toJson", "fromMap", - "toMap", + "toMap" ]; const typeNamingFunction = funPrefixNamer("types", n => dartNameStyle(true, false, n)); @@ -183,16 +181,16 @@ const enumCaseNamingFunction = funPrefixNamer("enum-cases", n => dartNameStyle(t // Escape the dollar sign, which is used in string interpolation const stringEscape = utf16ConcatMap( - escapeNonPrintableMapper(cp => isPrintable(cp) && cp !== 0x24, standardUnicodeHexEscape), + escapeNonPrintableMapper(cp => isPrintable(cp) && cp !== 0x24, standardUnicodeHexEscape) ); -function isStartCharacter (codePoint: number): boolean { +function isStartCharacter(codePoint: number): boolean { if (codePoint === 0x5f) return false; // underscore return isAscii(codePoint) && isLetter(codePoint); } -function isPartCharacter (codePoint: number): boolean { - return isStartCharacter(codePoint) || isAscii(codePoint) && isDigit(codePoint); +function isPartCharacter(codePoint: number): boolean { + return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); @@ -201,13 +199,13 @@ const legalizeName = utf16LegalizeCharacters(isPartCharacter); // we have to use namers to produce the getter and setter names - we can't // just capitalize and concatenate. // https://stackoverflow.com/questions/8277355/naming-convention-for-upper-case-abbreviations -function dartNameStyle (startWithUpper: boolean, upperUnderscore: boolean, original: string): string { +function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, original: string): string { const words = splitIntoWords(original); const firstWordStyle = upperUnderscore ? allUpperWordStyle : startWithUpper - ? firstUpperWordStyle - : allLowerWordStyle; + ? firstUpperWordStyle + : allLowerWordStyle; const restWordStyle = upperUnderscore ? allUpperWordStyle : firstUpperWordStyle; return combineWords( words, @@ -217,7 +215,7 @@ function dartNameStyle (startWithUpper: boolean, upperUnderscore: boolean, origi firstWordStyle, restWordStyle, upperUnderscore ? "_" : "", - isStartCharacter, + isStartCharacter ); } @@ -239,104 +237,104 @@ export class DartRenderer extends ConvenienceRenderer { private readonly _enumValues = new Map(); - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return typeNamingFunction; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return propertyNamingFunction; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return propertyNamingFunction; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return enumCaseNamingFunction; } - protected unionNeedsName (u: UnionType): boolean { + protected unionNeedsName(u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { // If the top-level type doesn't contain any classes or unions // we have to define a class just for the `FromJson` method, in // emitFromJsonForTopLevel. return directlyReachableSingleNamedType(type); } - protected get toJson (): string { + protected get toJson(): string { return `to${this._options.methodNamesWithMap ? "Map" : "Json"}`; } - protected get fromJson (): string { + protected get fromJson(): string { return `from${this._options.methodNamesWithMap ? "Map" : "Json"}`; } - protected makeTopLevelDependencyNames (_t: Type, name: Name): DependencyName[] { + protected makeTopLevelDependencyNames(_t: Type, name: Name): DependencyName[] { const encoder = new DependencyName( propertyNamingFunction, name.order, - lookup => `${lookup(name)}_${this.toJson}`, + lookup => `${lookup(name)}_${this.toJson}` ); const decoder = new DependencyName( propertyNamingFunction, name.order, - lookup => `${lookup(name)}_${this.fromJson}`, + lookup => `${lookup(name)}_${this.fromJson}` ); this._topLevelDependents.set(name, { encoder, decoder }); return [encoder, decoder]; } - protected makeNamesForPropertyGetterAndSetter ( + protected makeNamesForPropertyGetterAndSetter( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name, + name: Name ): [Name, Name] { const getterName = new DependencyName(propertyNamingFunction, name.order, lookup => `get_${lookup(name)}`); const setterName = new DependencyName(propertyNamingFunction, name.order, lookup => `set_${lookup(name)}`); return [getterName, setterName]; } - protected makePropertyDependencyNames ( + protected makePropertyDependencyNames( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name, + name: Name ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return getterAndSetterNames; } - protected makeNamedTypeDependencyNames (t: Type, name: Name): DependencyName[] { + protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { if (!(t instanceof EnumType)) return []; const enumValue = new DependencyName(propertyNamingFunction, name.order, lookup => `${lookup(name)}_values`); this._enumValues.set(t, enumValue); return [enumValue]; } - protected emitFileHeader (): void { + protected emitFileHeader(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } @@ -377,7 +375,7 @@ export class DartRenderer extends ConvenienceRenderer { // FIXME: This should use a `Name`, not `modifySource` const name = modifySource( snakeCase, - optionNameIsEmpty ? [...this.topLevels.keys()][0] : this._options.partName, + optionNameIsEmpty ? [...this.topLevels.keys()][0] : this._options.partName ); if (this._options.useFreezed) { this.emitLine("part '", name, ".freezed.dart';"); @@ -389,20 +387,20 @@ export class DartRenderer extends ConvenienceRenderer { } } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: "///", beforeComment: "" }); } - protected emitBlock (line: Sourcelike, f: () => void): void { + protected emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected dartType (t: Type, withIssues = false, forceNullable = false): Sourcelike { + protected dartType(t: Type, withIssues = false, forceNullable = false): Sourcelike { const nullable = - forceNullable || this._options.nullSafety && t.isNullable && !this._options.requiredProperties; - const withNullable = (s: Sourcelike): Sourcelike => nullable ? [s, "?"] : s; + forceNullable || (this._options.nullSafety && t.isNullable && !this._options.requiredProperties); + const withNullable = (s: Sourcelike): Sourcelike => (nullable ? [s, "?"] : s); return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "dynamic"), @@ -431,11 +429,11 @@ export class DartRenderer extends ConvenienceRenderer { default: return withNullable("String"); } - }, + } ); } - protected mapList (isNullable: boolean, itemType: Sourcelike, list: Sourcelike, mapper: Sourcelike): Sourcelike { + protected mapList(isNullable: boolean, itemType: Sourcelike, list: Sourcelike, mapper: Sourcelike): Sourcelike { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return [list, " == null ? [] : ", "List<", itemType, ">.from(", list, "!.map((x) => ", mapper, "))"]; } @@ -443,7 +441,7 @@ export class DartRenderer extends ConvenienceRenderer { return ["List<", itemType, ">.from(", list, ".map((x) => ", mapper, "))"]; } - protected mapMap (isNullable: boolean, valueType: Sourcelike, map: Sourcelike, valueMapper: Sourcelike): Sourcelike { + protected mapMap(isNullable: boolean, valueType: Sourcelike, map: Sourcelike, valueMapper: Sourcelike): Sourcelike { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return ["Map.from(", map, "!).map((k, v) => MapEntry(k, ", valueMapper, "))"]; } @@ -451,7 +449,7 @@ export class DartRenderer extends ConvenienceRenderer { return ["Map.from(", map, ").map((k, v) => MapEntry(k, ", valueMapper, "))"]; } - protected mapClass (isNullable: boolean, classType: ClassType, dynamic: Sourcelike) { + protected mapClass(isNullable: boolean, classType: ClassType, dynamic: Sourcelike) { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return [ dynamic, @@ -461,7 +459,7 @@ export class DartRenderer extends ConvenienceRenderer { this.fromJson, "(", dynamic, - ")", + ")" ]; } @@ -471,7 +469,7 @@ export class DartRenderer extends ConvenienceRenderer { // If the first time is the unionType type, after nullableFromUnion conversion, // the isNullable property will become false, which is obviously wrong, // so add isNullable property - protected fromDynamicExpression (isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { + protected fromDynamicExpression(isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, _anyType => dynamic, @@ -485,7 +483,7 @@ export class DartRenderer extends ConvenienceRenderer { isNullable || arrayType.isNullable, this.dartType(arrayType.items), dynamic, - this.fromDynamicExpression(arrayType.items.isNullable, arrayType.items, "x"), + this.fromDynamicExpression(arrayType.items.isNullable, arrayType.items, "x") ), classType => this.mapClass(isNullable || classType.isNullable, classType, dynamic), mapType => @@ -493,14 +491,14 @@ export class DartRenderer extends ConvenienceRenderer { mapType.isNullable || isNullable, this.dartType(mapType.values), dynamic, - this.fromDynamicExpression(mapType.values.isNullable, mapType.values, "v"), + this.fromDynamicExpression(mapType.values.isNullable, mapType.values, "v") ), enumType => { return [ defined(this._enumValues.get(enumType)), ".map[", dynamic, - this._options.nullSafety ? "]!" : "]", + this._options.nullSafety ? "]!" : "]" ]; }, unionType => { @@ -527,14 +525,14 @@ export class DartRenderer extends ConvenienceRenderer { default: return dynamic; } - }, + } ); } // If the first time is the unionType type, after nullableFromUnion conversion, // the isNullable property will become false, which is obviously wrong, // so add isNullable property - protected toDynamicExpression (isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { + protected toDynamicExpression(isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, _anyType => dynamic, @@ -548,7 +546,7 @@ export class DartRenderer extends ConvenienceRenderer { arrayType.isNullable || isNullable, "dynamic", dynamic, - this.toDynamicExpression(arrayType.items.isNullable, arrayType.items, "x"), + this.toDynamicExpression(arrayType.items.isNullable, arrayType.items, "x") ), _classType => { if ( @@ -566,7 +564,7 @@ export class DartRenderer extends ConvenienceRenderer { mapType.isNullable || isNullable, "dynamic", dynamic, - this.toDynamicExpression(mapType.values.isNullable, mapType.values, "v"), + this.toDynamicExpression(mapType.values.isNullable, mapType.values, "v") ), enumType => { return [defined(this._enumValues.get(enumType)), ".reverse[", dynamic, "]"]; @@ -598,45 +596,45 @@ export class DartRenderer extends ConvenienceRenderer { (transformedStringType.isNullable || isNullable) ) { return [ - "\"${", + '"${', dynamic, "!.year.toString().padLeft(4, '0')", "}-${", dynamic, "!.month.toString().padLeft(2, '0')}-${", dynamic, - "!.day.toString().padLeft(2, '0')}\"", + "!.day.toString().padLeft(2, '0')}\"" ]; } return [ - "\"${", + '"${', dynamic, ".year.toString().padLeft(4, '0')", "}-${", dynamic, ".month.toString().padLeft(2, '0')}-${", dynamic, - ".day.toString().padLeft(2, '0')}\"", + ".day.toString().padLeft(2, '0')}\"" ]; default: return dynamic; } - }, + } ); } - private _emitEmptyConstructor (className: Name): void { + private _emitEmptyConstructor(className: Name): void { this.emitLine(className, "();"); } - private _emitConstructor (c: ClassType, className: Name): void { + private _emitConstructor(c: ClassType, className: Name): void { this.emitLine(className, "({"); this.indent(() => { this.forEachClassProperty(c, "none", (name, _, prop) => { const required = this._options.requiredProperties || - this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional); + (this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional)); this.emitLine(required ? "required " : "", "this.", name, ","); }); }); @@ -644,7 +642,7 @@ export class DartRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - private _emitVariables (c: ClassType): void { + private _emitVariables(c: ClassType): void { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const description = this.descriptionForClassProperty(c, jsonName); if (description !== undefined) { @@ -665,7 +663,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - private _emitCopyConstructor (c: ClassType, className: Name): void { + private _emitCopyConstructor(c: ClassType, className: Name): void { this.ensureBlankLine(); this.emitLine(className, " copyWith({"); this.indent(() => { @@ -685,7 +683,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - private _emitStringJsonEncoderDecoder (className: Name): void { + private _emitStringJsonEncoderDecoder(className: Name): void { this.ensureBlankLine(); this.emitLine( "factory ", @@ -696,7 +694,7 @@ export class DartRenderer extends ConvenienceRenderer { className, ".", this.fromJson, - "(json.decode(str));", + "(json.decode(str));" ); this.ensureBlankLine(); @@ -705,11 +703,11 @@ export class DartRenderer extends ConvenienceRenderer { this._options.methodNamesWithMap ? "toJson() => " : "toRawJson() => ", "json.encode(", this.toJson, - "());", + "());" ); } - private _emitMapEncoderDecoder (c: ClassType, className: Name): void { + private _emitMapEncoderDecoder(c: ClassType, className: Name): void { this.ensureBlankLine(); this.emitLine("factory ", className, ".", this.fromJson, "(Map json) => ", className, "("); this.indent(() => { @@ -720,11 +718,11 @@ export class DartRenderer extends ConvenienceRenderer { this.fromDynamicExpression( property.type.isNullable, property.type, - "json[\"", + 'json["', stringEscape(jsonName), - "\"]", + '"]' ), - ",", + "," ); }); }); @@ -736,18 +734,18 @@ export class DartRenderer extends ConvenienceRenderer { this.indent(() => { this.forEachClassProperty(c, "none", (name, jsonName, property) => { this.emitLine( - "\"", + '"', stringEscape(jsonName), - "\": ", + '": ', this.toDynamicExpression(property.type.isNullable, property.type, name), - ",", + "," ); }); }); this.emitLine("};"); } - protected emitClassDefinition (c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); if (this._options.useHive) { this.classCounter++; @@ -781,7 +779,7 @@ export class DartRenderer extends ConvenienceRenderer { ".fromJson(Map json) => ", "_$", className, - "FromJson(json);", + "FromJson(json);" ); this.ensureBlankLine(); @@ -790,7 +788,7 @@ export class DartRenderer extends ConvenienceRenderer { "Map toJson() => ", "_$", className, - "ToJson(this);", + "ToJson(this);" ); } else { if (this._options.justTypes) return; @@ -804,7 +802,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - protected emitFreezedClassDefinition (c: ClassType, className: Name): void { + protected emitFreezedClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitLine("@freezed"); @@ -822,7 +820,7 @@ export class DartRenderer extends ConvenienceRenderer { const required = this._options.requiredProperties || - this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional); + (this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional)); if (this._options.useJsonAnnotation) { this.classPropertyCounter++; this.emitLine(`@JsonKey(name: "${jsonName}")`); @@ -844,19 +842,19 @@ export class DartRenderer extends ConvenienceRenderer { ".fromJson(Map json) => ", "_$", className, - "FromJson(json);", + "FromJson(json);" ); }); } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine("enum ", enumName, " {"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName, pos) => { const comma = pos === "first" || pos === "middle" ? "," : []; if (this._options.useJsonAnnotation) { - this.emitLine("@JsonValue(\"", stringEscape(jsonName), "\")"); + this.emitLine('@JsonValue("', stringEscape(jsonName), '")'); } this.emitLine(name, comma); @@ -871,7 +869,7 @@ export class DartRenderer extends ConvenienceRenderer { this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName, pos) => { const comma = pos === "first" || pos === "middle" ? "," : []; - this.emitLine("\"", stringEscape(jsonName), "\": ", enumName, ".", name, comma); + this.emitLine('"', stringEscape(jsonName), '": ', enumName, ".", name, comma); }); }); this.emitLine("});"); @@ -879,7 +877,7 @@ export class DartRenderer extends ConvenienceRenderer { this._needEnumValues = true; } - protected emitEnumValues (): void { + protected emitEnumValues(): void { this.ensureBlankLine(); this.emitMultiline(`class EnumValues { Map map; @@ -894,7 +892,7 @@ export class DartRenderer extends ConvenienceRenderer { }`); } - private _emitTopLvlEncoderDecoder (): void { + private _emitTopLvlEncoderDecoder(): void { this.forEachTopLevel("leading-and-interposing", (t, name) => { const { encoder, decoder } = defined(this._topLevelDependents.get(name)); @@ -904,7 +902,7 @@ export class DartRenderer extends ConvenienceRenderer { decoder, "(String str) => ", this.fromDynamicExpression(t.isNullable, t, "json.decode(str)"), - ";", + ";" ); this.ensureBlankLine(); @@ -916,7 +914,7 @@ export class DartRenderer extends ConvenienceRenderer { this.dartType(t), " data) => json.encode(", this.toDynamicExpression(t.isNullable, t, "data"), - ");", + ");" ); // this.emitBlock(["String ", encoder, "(", this.dartType(t), " data)"], () => { @@ -925,7 +923,7 @@ export class DartRenderer extends ConvenienceRenderer { }); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.emitFileHeader(); if (!this._options.justTypes && !this._options.codersInClass) { @@ -939,7 +937,7 @@ export class DartRenderer extends ConvenienceRenderer { (e, n) => this.emitEnumDefinition(e, n), (_e, _n) => { // We don't support this yet. - }, + } ); if (this._needEnumValues) { diff --git a/packages/quicktype-core/src/language/Elm.ts b/packages/quicktype-core/src/language/Elm.ts index 01fa4f807..a9c81776e 100644 --- a/packages/quicktype-core/src/language/Elm.ts +++ b/packages/quicktype-core/src/language/Elm.ts @@ -8,7 +8,7 @@ import { UnionType } from "../Type"; import { matchType, nullableFromUnion } from "../TypeUtils"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Namer, type Name} from "../Naming"; +import { type Namer, type Name } from "../Naming"; import { DependencyName, funPrefixNamer } from "../Naming"; import { legalizeCharacters, @@ -21,10 +21,10 @@ import { combineWords, firstUpperWordStyle, allLowerWordStyle, - allUpperWordStyle, + allUpperWordStyle } from "../support/Strings"; import { defined } from "../support/Support"; -import { type Sourcelike, type MultiWord} from "../Source"; +import { type Sourcelike, type MultiWord } from "../Source"; import { annotated, singleWord, multiWord, parenIfNeeded } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type RenderContext } from "../Renderer"; @@ -33,30 +33,30 @@ export const elmOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), useList: new EnumOption("array-type", "Use Array or List", [ ["array", false], - ["list", true], + ["list", true] ]), // FIXME: Do this via a configurable named eventually. - moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType"), + moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") }; export class ElmTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Elm", ["elm"], "elm"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [elmOptions.justTypes, elmOptions.moduleName, elmOptions.useList]; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): ElmRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): ElmRenderer { return new ElmRenderer(this, renderContext, getOptionValues(elmOptions, untypedOptionValues)); } } @@ -99,12 +99,12 @@ const forbiddenNames = [ "True", "False", "String", - "Float", + "Float" ]; const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); -function elmNameStyle (original: string, upper: boolean): string { +function elmNameStyle(original: string, upper: boolean): string { const words = splitIntoWords(original); return combineWords( words, @@ -114,7 +114,7 @@ function elmNameStyle (original: string, upper: boolean): string { upper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore, + isLetterOrUnderscore ); } @@ -126,13 +126,13 @@ interface RequiredOrOptional { reqOrOpt: string; } -function requiredOrOptional (p: ClassProperty): RequiredOrOptional { - function optional (fallback: string): RequiredOrOptional { +function requiredOrOptional(p: ClassProperty): RequiredOrOptional { + function optional(fallback: string): RequiredOrOptional { return { reqOrOpt: "Jpipe.optional", fallback }; } const t = p.type; - if (p.isOptional || t instanceof UnionType && nullableFromUnion(t) !== null) { + if (p.isOptional || (t instanceof UnionType && nullableFromUnion(t) !== null)) { return optional(" Nothing"); } @@ -158,23 +158,23 @@ export class ElmRenderer extends ConvenienceRenderer { private readonly _namedTypeDependents = new Map(); - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return forbiddenNames; } - protected makeTopLevelDependencyNames (t: Type, topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames(t: Type, topLevelName: Name): DependencyName[] { const encoder = new DependencyName( lowerNamingFunction, topLevelName.order, - lookup => `${lookup(topLevelName)}_to_string`, + lookup => `${lookup(topLevelName)}_to_string` ); let decoder: DependencyName | undefined = undefined; if (this.namedTypeToNameForTopLevel(t) === undefined) { @@ -189,56 +189,56 @@ export class ElmRenderer extends ConvenienceRenderer { return [encoder]; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return upperNamingFunction; } - protected makeNamedTypeDependencyNames (_: Type, typeName: Name): DependencyName[] { + protected makeNamedTypeDependencyNames(_: Type, typeName: Name): DependencyName[] { const encoder = new DependencyName(lowerNamingFunction, typeName.order, lookup => `encode_${lookup(typeName)}`); const decoder = new DependencyName(lowerNamingFunction, typeName.order, lookup => lookup(typeName)); this._namedTypeDependents.set(typeName, { encoder, decoder }); return [encoder, decoder]; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return lowerNamingFunction; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return upperNamingFunction; } - protected get unionMembersInGlobalNamespace (): boolean { + protected get unionMembersInGlobalNamespace(): boolean { return true; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return upperNamingFunction; } - protected get enumCasesInGlobalNamespace (): boolean { + protected get enumCasesInGlobalNamespace(): boolean { return true; } - protected proposeUnionMemberName ( + protected proposeUnionMemberName( u: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string, + lookup: (n: Name) => string ): string { const fieldName = super.proposeUnionMemberName(u, unionName, fieldType, lookup); return `${fieldName}_in_${lookup(unionName)}`; } - protected get commentLineStart (): string { + protected get commentLineStart(): string { return "-- "; } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { if (lines.length === 1) { this.emitComments([{ customLines: lines, lineStart: "{-| ", lineEnd: " -}" }]); } else { @@ -246,11 +246,11 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private get arrayType (): string { + private get arrayType(): string { return this._options.useList ? "List" : "Array"; } - private elmType (t: Type, noOptional = false): MultiWord { + private elmType(t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => singleWord(annotated(anyTypeIssueAnnotation, "Jdec.Value")), @@ -272,11 +272,11 @@ export class ElmRenderer extends ConvenienceRenderer { } return singleWord(this.nameForNamedType(unionType)); - }, + } ); } - private elmProperty (p: ClassProperty): Sourcelike { + private elmProperty(p: ClassProperty): Sourcelike { if (p.isOptional) { return multiWord(" ", "Maybe", parenIfNeeded(this.elmType(p.type, true))).source; } else { @@ -284,12 +284,12 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private decoderNameForNamedType (t: Type): Name { + private decoderNameForNamedType(t: Type): Name { const name = this.nameForNamedType(t); return defined(this._namedTypeDependents.get(name)).decoder; } - private decoderNameForType (t: Type, noOptional = false): MultiWord { + private decoderNameForType(t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => singleWord("Jdec.value"), @@ -302,7 +302,7 @@ export class ElmRenderer extends ConvenienceRenderer { multiWord( " ", ["Jdec.", decapitalize(this.arrayType)], - parenIfNeeded(this.decoderNameForType(arrayType.items)), + parenIfNeeded(this.decoderNameForType(arrayType.items)) ), classType => singleWord(this.decoderNameForNamedType(classType)), mapType => multiWord(" ", "Jdec.dict", parenIfNeeded(this.decoderNameForType(mapType.values))), @@ -316,11 +316,11 @@ export class ElmRenderer extends ConvenienceRenderer { } return singleWord(this.decoderNameForNamedType(unionType)); - }, + } ); } - private decoderNameForProperty (p: ClassProperty): MultiWord { + private decoderNameForProperty(p: ClassProperty): MultiWord { if (p.isOptional) { return multiWord(" ", "Jdec.nullable", parenIfNeeded(this.decoderNameForType(p.type, true))); } else { @@ -328,12 +328,12 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private encoderNameForNamedType (t: Type): Name { + private encoderNameForNamedType(t: Type): Name { const name = this.nameForNamedType(t); return defined(this._namedTypeDependents.get(name)).encoder; } - private encoderNameForType (t: Type, noOptional = false): MultiWord { + private encoderNameForType(t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => singleWord("identity"), @@ -346,7 +346,7 @@ export class ElmRenderer extends ConvenienceRenderer { multiWord( " ", ["make", this.arrayType, "Encoder"], - parenIfNeeded(this.encoderNameForType(arrayType.items)), + parenIfNeeded(this.encoderNameForType(arrayType.items)) ), classType => singleWord(this.encoderNameForNamedType(classType)), mapType => multiWord(" ", "makeDictEncoder", parenIfNeeded(this.encoderNameForType(mapType.values))), @@ -360,11 +360,11 @@ export class ElmRenderer extends ConvenienceRenderer { } return singleWord(this.encoderNameForNamedType(unionType)); - }, + } ); } - private encoderNameForProperty (p: ClassProperty): MultiWord { + private encoderNameForProperty(p: ClassProperty): MultiWord { if (p.isOptional) { return multiWord(" ", "makeNullableEncoder", parenIfNeeded(this.encoderNameForType(p.type, true))); } else { @@ -372,11 +372,11 @@ export class ElmRenderer extends ConvenienceRenderer { } } - private emitTopLevelDefinition (t: Type, topLevelName: Name): void { + private emitTopLevelDefinition(t: Type, topLevelName: Name): void { this.emitLine("type alias ", topLevelName, " = ", this.elmType(t).source); } - private emitClassDefinition (c: ClassType, className: Name): void { + private emitClassDefinition(c: ClassType, className: Name): void { let description = this.descriptionForType(c); this.forEachClassProperty(c, "none", (name, jsonName) => { const propertyDescription = this.descriptionForClassProperty(c, jsonName); @@ -408,7 +408,7 @@ export class ElmRenderer extends ConvenienceRenderer { }); } - private emitEnumDefinition (e: EnumType, enumName: Name): void { + private emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine("type ", enumName); this.indent(() => { @@ -421,7 +421,7 @@ export class ElmRenderer extends ConvenienceRenderer { }); } - private emitUnionDefinition (u: UnionType, unionName: Name): void { + private emitUnionDefinition(u: UnionType, unionName: Name): void { this.emitDescription(this.descriptionForType(u)); this.emitLine("type ", unionName); this.indent(() => { @@ -439,7 +439,7 @@ export class ElmRenderer extends ConvenienceRenderer { }); } - private emitTopLevelFunctions (t: Type, topLevelName: Name): void { + private emitTopLevelFunctions(t: Type, topLevelName: Name): void { const { encoder, decoder } = defined(this._topLevelDependents.get(topLevelName)); if (this.namedTypeToNameForTopLevel(t) === undefined) { this.emitLine(defined(decoder), " : Jdec.Decoder ", topLevelName); @@ -451,7 +451,7 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine(encoder, " r = Jenc.encode 0 (", this.encoderNameForType(t).source, " r)"); } - private emitClassFunctions (c: ClassType, className: Name): void { + private emitClassFunctions(c: ClassType, className: Name): void { const decoderName = this.decoderNameForNamedType(c); this.emitLine(decoderName, " : Jdec.Decoder ", className); this.emitLine(decoderName, " ="); @@ -461,7 +461,7 @@ export class ElmRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (_, jsonName, p) => { const propDecoder = parenIfNeeded(this.decoderNameForProperty(p)); const { reqOrOpt, fallback } = requiredOrOptional(p); - this.emitLine("|> ", reqOrOpt, " \"", stringEscape(jsonName), "\" ", propDecoder, fallback); + this.emitLine("|> ", reqOrOpt, ' "', stringEscape(jsonName), '" ', propDecoder, fallback); }); }); }); @@ -477,7 +477,7 @@ export class ElmRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const bracketOrComma = onFirst ? "[" : ","; const propEncoder = this.encoderNameForProperty(p).source; - this.emitLine(bracketOrComma, " (\"", stringEscape(jsonName), "\", ", propEncoder, " x.", name, ")"); + this.emitLine(bracketOrComma, ' ("', stringEscape(jsonName), '", ', propEncoder, " x.", name, ")"); onFirst = false; }); if (onFirst) { @@ -489,7 +489,7 @@ export class ElmRenderer extends ConvenienceRenderer { }); } - private emitEnumFunctions (e: EnumType, enumName: Name): void { + private emitEnumFunctions(e: EnumType, enumName: Name): void { const decoderName = this.decoderNameForNamedType(e); this.emitLine(decoderName, " : Jdec.Decoder ", enumName); this.emitLine(decoderName, " ="); @@ -501,9 +501,9 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine("case str of"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("\"", stringEscape(jsonName), "\" -> Jdec.succeed ", name); + this.emitLine('"', stringEscape(jsonName), '" -> Jdec.succeed ', name); }); - this.emitLine("somethingElse -> Jdec.fail <| \"Invalid ", enumName, ": \" ++ somethingElse"); + this.emitLine('somethingElse -> Jdec.fail <| "Invalid ', enumName, ': " ++ somethingElse'); }); }); this.emitLine(")"); @@ -516,14 +516,14 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine(encoderName, " x = case x of"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine(name, " -> Jenc.string \"", stringEscape(jsonName), "\""); + this.emitLine(name, ' -> Jenc.string "', stringEscape(jsonName), '"'); }); }); } - private emitUnionFunctions (u: UnionType, unionName: Name): void { + private emitUnionFunctions(u: UnionType, unionName: Name): void { // We need arrays first, then strings, and integers before doubles. - function sortOrder (_: Name, t: Type): string { + function sortOrder(_: Name, t: Type): string { if (t.kind === "array") { return " array"; } else if (t.kind === "double") { @@ -573,7 +573,7 @@ export class ElmRenderer extends ConvenienceRenderer { }); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { const exports: Sourcelike[] = []; const topLevelDecoders: Sourcelike[] = []; this.forEachTopLevel("none", (_, name) => { @@ -605,14 +605,14 @@ export class ElmRenderer extends ConvenienceRenderer { "", "add these imports", "", - " import Json.Decode exposing (decodeString)`);", + " import Json.Decode exposing (decodeString)`);" ]); this.emitLine( "-- import ", this._options.moduleName, " exposing (", arrayIntercalate(", ", topLevelDecoders), - ")", + ")" ); this.emitMultiline(`-- -- and you're off to the races with @@ -653,13 +653,13 @@ import Dict exposing (Dict, map, toList)`); this.forEachTopLevel( "leading-and-interposing", (t: Type, topLevelName: Name) => this.emitTopLevelDefinition(t, topLevelName), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassDefinition(c, className), (e: EnumType, enumName: Name) => this.emitEnumDefinition(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName), + (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName) ); if (this._options.justTypes) return; @@ -667,13 +667,13 @@ import Dict exposing (Dict, map, toList)`); this.ensureBlankLine(); this.emitLine("-- decoders and encoders"); this.forEachTopLevel("leading-and-interposing", (t: Type, topLevelName: Name) => - this.emitTopLevelFunctions(t, topLevelName), + this.emitTopLevelFunctions(t, topLevelName) ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassFunctions(c, className), (e: EnumType, enumName: Name) => this.emitEnumFunctions(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName), + (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName) ); this.ensureBlankLine(); diff --git a/packages/quicktype-core/src/language/Golang.ts b/packages/quicktype-core/src/language/Golang.ts index c41a6af26..0dd4afcb5 100644 --- a/packages/quicktype-core/src/language/Golang.ts +++ b/packages/quicktype-core/src/language/Golang.ts @@ -1,7 +1,7 @@ import { type TypeKind, type Type, type ClassType, type EnumType, type ClassProperty } from "../Type"; import { UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { DependencyName, funPrefixNamer } from "../Naming"; import { legalizeCharacters, @@ -12,12 +12,12 @@ import { combineWords, firstUpperWordStyle, allUpperWordStyle, - camelCase, + camelCase } from "../support/Strings"; import { assert, defined } from "../support/Support"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { StringOption, BooleanOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated, modifySource } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { TargetLanguage } from "../TargetLanguage"; @@ -33,46 +33,46 @@ export const goOptions = { fieldTags: new StringOption("field-tags", "list of tags which should be generated for fields", "TAGS", "json"), omitEmpty: new BooleanOption( "omit-empty", - "If set, all non-required objects will be tagged with \",omitempty\"", - false, - ), + 'If set, all non-required objects will be tagged with ",omitempty"', + false + ) }; export class GoTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Go", ["go", "golang"], "go"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ goOptions.justTypes, goOptions.justTypesAndPackage, goOptions.packageName, goOptions.multiFileOutput, goOptions.fieldTags, - goOptions.omitEmpty, + goOptions.omitEmpty ]; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date-time", "date-time"); return mapping; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): GoRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): GoRenderer { return new GoRenderer(this, renderContext, getOptionValues(goOptions, untypedOptionValues)); } - protected get defaultIndentation (): string { + protected get defaultIndentation(): string { return "\t"; } } @@ -81,7 +81,7 @@ const namingFunction = funPrefixNamer("namer", goNameStyle); const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); -function goNameStyle (original: string): string { +function goNameStyle(original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -91,19 +91,19 @@ function goNameStyle (original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore, + isLetterOrUnderscore ); } const primitiveValueTypeKinds: TypeKind[] = ["integer", "double", "bool", "string"]; const compoundTypeKinds: TypeKind[] = ["array", "class", "map", "enum"]; -function isValueType (t: Type): boolean { +function isValueType(t: Type): boolean { const kind = t.kind; return primitiveValueTypeKinds.includes(kind) || kind === "class" || kind === "enum" || kind === "date-time"; } -function canOmitEmpty (cp: ClassProperty, omitEmptyOption: boolean): boolean { +function canOmitEmpty(cp: ClassProperty, omitEmptyOption: boolean): boolean { if (!cp.isOptional) return false; if (omitEmptyOption) return true; const t = cp.type; @@ -115,46 +115,46 @@ export class GoRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return namingFunction; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return namingFunction; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return namingFunction; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return namingFunction; } - protected get enumCasesInGlobalNamespace (): boolean { + protected get enumCasesInGlobalNamespace(): boolean { return true; } - protected makeTopLevelDependencyNames (_: Type, topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames(_: Type, topLevelName: Name): DependencyName[] { const unmarshalName = new DependencyName( namingFunction, topLevelName.order, - lookup => `unmarshal_${lookup(topLevelName)}`, + lookup => `unmarshal_${lookup(topLevelName)}` ); this._topLevelUnmarshalNames.set(topLevelName, unmarshalName); return [unmarshalName]; } /// startFile takes a file name, lowercases it, appends ".go" to it, and sets it as the current filename. - protected startFile (basename: Sourcelike): void { + protected startFile(basename: Sourcelike): void { if (this._options.multiFileOutput === false) { return; } @@ -165,7 +165,7 @@ export class GoRenderer extends ConvenienceRenderer { } /// endFile pushes the current file name onto the collection of finished files and then resets the current file name. These finished files are used in index.ts to write the output. - protected endFile (): void { + protected endFile(): void { if (this._options.multiFileOutput === false) { return; } @@ -174,21 +174,21 @@ export class GoRenderer extends ConvenienceRenderer { this._currentFilename = undefined; } - private emitBlock (line: Sourcelike, f: () => void): void { + private emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - private emitFunc (decl: Sourcelike, f: () => void): void { + private emitFunc(decl: Sourcelike, f: () => void): void { this.emitBlock(["func ", decl], f); } - private emitStruct (name: Name, table: Sourcelike[][]): void { + private emitStruct(name: Name, table: Sourcelike[][]): void { this.emitBlock(["type ", name, " struct"], () => this.emitTable(table)); } - private nullableGoType (t: Type, withIssues: boolean): Sourcelike { + private nullableGoType(t: Type, withIssues: boolean): Sourcelike { const goType = this.goType(t, withIssues); if (isValueType(t)) { return ["*", goType]; @@ -197,7 +197,7 @@ export class GoRenderer extends ConvenienceRenderer { } } - private propertyGoType (cp: ClassProperty): Sourcelike { + private propertyGoType(cp: ClassProperty): Sourcelike { const t = cp.type; if (t instanceof UnionType && nullableFromUnion(t) === null) { return ["*", this.goType(t, true)]; @@ -210,7 +210,7 @@ export class GoRenderer extends ConvenienceRenderer { return this.goType(t, true); } - private goType (t: Type, withIssues = false): Sourcelike { + private goType(t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "interface{}"), @@ -244,11 +244,11 @@ export class GoRenderer extends ConvenienceRenderer { } return "string"; - }, + } ); } - private emitTopLevel (t: Type, name: Name): void { + private emitTopLevel(t: Type, name: Name): void { this.startFile(name); if ( @@ -258,7 +258,7 @@ export class GoRenderer extends ConvenienceRenderer { this.leadingComments === undefined ) { this.emitLineOnce( - "// This file was generated from JSON Schema using quicktype, do not modify it directly.", + "// This file was generated from JSON Schema using quicktype, do not modify it directly." ); this.emitLineOnce("// To parse and unparse this JSON data, add this code to your project and do:"); this.emitLineOnce("//"); @@ -289,7 +289,7 @@ export class GoRenderer extends ConvenienceRenderer { this.endFile(); } - private emitClass (c: ClassType, className: Name): void { + private emitClass(c: ClassType, className: Name): void { this.startFile(className); let columns: Sourcelike[][] = []; const usedTypes = new Set(); @@ -303,12 +303,12 @@ export class GoRenderer extends ConvenienceRenderer { docStrings.forEach(doc => columns.push([doc])); const tags = this._options.fieldTags .split(",") - .map(tag => tag + ":\"" + stringEscape(jsonName) + omitEmpty + "\"") + .map(tag => tag + ':"' + stringEscape(jsonName) + omitEmpty + '"') .join(" "); columns.push([ [name, " "], [goType, " "], - ["`", tags, "`"], + ["`", tags, "`"] ]); usedTypes.add(goType.toString()); }); @@ -317,14 +317,14 @@ export class GoRenderer extends ConvenienceRenderer { false, usedTypes.has("time.Time") || usedTypes.has("*,time.Time") || usedTypes.has("[],time.Time") ? new Set(["time"]) - : undefined, + : undefined ); this.emitDescription(this.descriptionForType(c)); this.emitStruct(className, columns); this.endFile(); } - private emitEnum (e: EnumType, enumName: Name): void { + private emitEnum(e: EnumType, enumName: Name): void { this.startFile(enumName); this.emitPackageDefinitons(false); this.emitDescription(this.descriptionForType(e)); @@ -335,7 +335,7 @@ export class GoRenderer extends ConvenienceRenderer { this.forEachEnumCase(e, "none", (name, jsonName) => { columns.push([ [name, " "], - [enumName, " = \"", stringEscape(jsonName), "\""], + [enumName, ' = "', stringEscape(jsonName), '"'] ]); }); this.indent(() => this.emitTable(columns)); @@ -343,7 +343,7 @@ export class GoRenderer extends ConvenienceRenderer { this.endFile(); } - private emitUnion (u: UnionType, unionName: Name): void { + private emitUnion(u: UnionType, unionName: Name): void { this.startFile(unionName); this.emitPackageDefinitons(false); const [hasNull, nonNulls] = removeNullFromUnion(u); @@ -367,20 +367,20 @@ export class GoRenderer extends ConvenienceRenderer { const makeArgs = ( primitiveArg: (fieldName: Sourcelike) => Sourcelike, - compoundArg: (isClass: boolean, fieldName: Sourcelike) => Sourcelike, + compoundArg: (isClass: boolean, fieldName: Sourcelike) => Sourcelike ): Sourcelike => { const args: Sourcelike = []; for (const kind of primitiveValueTypeKinds) { args.push( ifMember(kind, "nil", (_1, fieldName, _2) => primitiveArg(fieldName)), - ", ", + ", " ); } for (const kind of compoundTypeKinds) { args.push( ifMember(kind, "false, nil", (t, fieldName, _) => compoundArg(t.kind === "class", fieldName)), - ", ", + ", " ); } @@ -415,7 +415,7 @@ export class GoRenderer extends ConvenienceRenderer { } else { return ["true, &x.", fn]; } - }, + } ); this.emitLine("object, err := unmarshalUnion(data, ", args, ")"); this.emitBlock("if err != nil", () => { @@ -432,14 +432,14 @@ export class GoRenderer extends ConvenienceRenderer { this.emitFunc(["(x *", unionName, ") MarshalJSON() ([]byte, error)"], () => { const args = makeArgs( fn => ["x.", fn], - (_, fn) => ["x.", fn, " != nil, x.", fn], + (_, fn) => ["x.", fn, " != nil, x.", fn] ); this.emitLine("return marshalUnion(", args, ")"); }); this.endFile(); } - private emitSingleFileHeaderComments (): void { + private emitSingleFileHeaderComments(): void { this.emitLineOnce("// This file was generated from JSON Schema using quicktype, do not modify it directly."); this.emitLineOnce("// To parse and unparse this JSON data, add this code to your project and do:"); this.forEachTopLevel("none", (_: Type, name: Name) => { @@ -450,7 +450,7 @@ export class GoRenderer extends ConvenienceRenderer { }); } - private emitPackageDefinitons (includeJSONEncodingImport: boolean, imports: Set = new Set()): void { + private emitPackageDefinitons(includeJSONEncodingImport: boolean, imports: Set = new Set()): void { if (!this._options.justTypes || this._options.justTypesAndPackage) { this.ensureBlankLine(); const packageDeclaration = "package " + this._options.packageName; @@ -472,7 +472,7 @@ export class GoRenderer extends ConvenienceRenderer { this.emitImports(imports); } - private emitImports (imports: Set): void { + private emitImports(imports: Set): void { const sortedImports = Array.from(imports).sort((a, b) => a.localeCompare(b)); if (sortedImports.length === 0) { @@ -485,7 +485,7 @@ export class GoRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - private emitHelperFunctions (): void { + private emitHelperFunctions(): void { if (this.haveNamedUnions) { this.startFile("JSONSchemaSupport"); const imports = new Set(); @@ -614,7 +614,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, } } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { if ( this._options.multiFileOutput === false && this._options.justTypes === false && @@ -630,7 +630,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, (t, name) => this.emitTopLevel(t, name), t => !(this._options.justTypes || this._options.justTypesAndPackage) || - this.namedTypeToNameForTopLevel(t) === undefined, + this.namedTypeToNameForTopLevel(t) === undefined ); this.forEachObject("leading-and-interposing", (c: ClassType, className: Name) => this.emitClass(c, className)); this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => this.emitEnum(u, enumName)); @@ -643,7 +643,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, this.emitHelperFunctions(); } - private collectAllImports (): Set { + private collectAllImports(): Set { let imports = new Set(); this.forEachObject("leading-and-interposing", (c: ClassType, _className: Name) => { const classImports = this.collectClassImports(c); @@ -657,7 +657,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, return imports; } - private collectClassImports (c: ClassType): Set { + private collectClassImports(c: ClassType): Set { const usedTypes = new Set(); const mapping: Map = new Map(); mapping.set("time.Time", "time"); @@ -680,7 +680,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, return imports; } - private collectUnionImports (u: UnionType): Set { + private collectUnionImports(u: UnionType): Set { const usedTypes = new Set(); const mapping: Map = new Map(); mapping.set("time.Time", "time"); diff --git a/packages/quicktype-core/src/language/Haskell.ts b/packages/quicktype-core/src/language/Haskell.ts index ed13a8ee7..f33ce9927 100644 --- a/packages/quicktype-core/src/language/Haskell.ts +++ b/packages/quicktype-core/src/language/Haskell.ts @@ -6,7 +6,7 @@ import { type Type, type ClassType, type UnionType, type EnumType, type ClassPro import { matchType, nullableFromUnion } from "../TypeUtils"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Namer, type Name} from "../Naming"; +import { type Namer, type Name } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { legalizeCharacters, @@ -18,9 +18,9 @@ import { combineWords, firstUpperWordStyle, allLowerWordStyle, - allUpperWordStyle, + allUpperWordStyle } from "../support/Strings"; -import { type Sourcelike, type MultiWord} from "../Source"; +import { type Sourcelike, type MultiWord } from "../Source"; import { singleWord, multiWord, parenIfNeeded } from "../Source"; import { type RenderContext } from "../Renderer"; @@ -28,31 +28,31 @@ export const haskellOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), useList: new EnumOption("array-type", "Use Array or List", [ ["array", false], - ["list", true], + ["list", true] ]), - moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType"), + moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") }; export class HaskellTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Haskell", ["haskell"], "haskell"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [haskellOptions.justTypes, haskellOptions.moduleName, haskellOptions.useList]; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): HaskellRenderer { return new HaskellRenderer(this, renderContext, getOptionValues(haskellOptions, untypedOptionValues)); } @@ -110,12 +110,12 @@ const forbiddenNames = [ "Object", "Result", "Series", - "Error", + "Error" ]; const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); -function haskellNameStyle (original: string, upper: boolean): string { +function haskellNameStyle(original: string, upper: boolean): string { const words = splitIntoWords(original); return combineWords( words, @@ -125,7 +125,7 @@ function haskellNameStyle (original: string, upper: boolean): string { upper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore, + isLetterOrUnderscore ); } @@ -133,73 +133,73 @@ const upperNamingFunction = funPrefixNamer("upper", n => haskellNameStyle(n, tru const lowerNamingFunction = funPrefixNamer("lower", n => haskellNameStyle(n, false)); export class HaskellRenderer extends ConvenienceRenderer { - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return forbiddenNames; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return upperNamingFunction; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return lowerNamingFunction; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return upperNamingFunction; } - protected get unionMembersInGlobalNamespace (): boolean { + protected get unionMembersInGlobalNamespace(): boolean { return true; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return upperNamingFunction; } - protected get enumCasesInGlobalNamespace (): boolean { + protected get enumCasesInGlobalNamespace(): boolean { return true; } - protected proposeUnionMemberName ( + protected proposeUnionMemberName( u: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string, + lookup: (n: Name) => string ): string { const fieldName = super.proposeUnionMemberName(u, unionName, fieldType, lookup); return `${fieldName}_in_${lookup(unionName)}`; } - protected get commentLineStart (): string { + protected get commentLineStart(): string { return "-- "; } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { if (lines.length === 1) { this.emitComments([{ customLines: lines, lineStart: "{-| ", lineEnd: " -}" }]); } else { this.emitCommentLines(lines, { firstLineStart: "{-| ", lineStart: "", - afterComment: "-}", + afterComment: "-}" }); } } - private haskellType (t: Type, noOptional = false): MultiWord { + private haskellType(t: Type, noOptional = false): MultiWord { return matchType( t, _anyType => multiWord(" ", "Maybe", "Text"), @@ -227,11 +227,11 @@ export class HaskellRenderer extends ConvenienceRenderer { } return singleWord(this.nameForNamedType(unionType)); - }, + } ); } - private haskellProperty (p: ClassProperty): Sourcelike { + private haskellProperty(p: ClassProperty): Sourcelike { if (p.isOptional) { return multiWord(" ", "Maybe", parenIfNeeded(this.haskellType(p.type, true))).source; } else { @@ -239,7 +239,7 @@ export class HaskellRenderer extends ConvenienceRenderer { } } - private encoderNameForType (t: Type): MultiWord { + private encoderNameForType(t: Type): MultiWord { return matchType( t, _anyType => singleWord("String"), @@ -252,15 +252,15 @@ export class HaskellRenderer extends ConvenienceRenderer { _classType => singleWord("Object"), _mapType => singleWord("Object"), _enumType => singleWord("Object"), - _unionType => singleWord("Object"), + _unionType => singleWord("Object") ); } - private emitTopLevelDefinition (t: Type, topLevelName: Name): void { + private emitTopLevelDefinition(t: Type, topLevelName: Name): void { this.emitLine("type ", topLevelName, " = ", this.haskellType(t).source); } - private emitClassDefinition (c: ClassType, className: Name): void { + private emitClassDefinition(c: ClassType, className: Name): void { let description = this.descriptionForType(c); this.forEachClassProperty(c, "none", (name, jsonName) => { const propertyDescription = this.descriptionForClassProperty(c, jsonName); @@ -292,7 +292,7 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitEnumDefinition (e: EnumType, enumName: Name): void { + private emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitLine("data ", enumName); this.indent(() => { @@ -306,7 +306,7 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitUnionDefinition (u: UnionType, unionName: Name): void { + private emitUnionDefinition(u: UnionType, unionName: Name): void { this.emitDescription(this.descriptionForType(u)); this.emitLine("data ", unionName); this.indent(() => { @@ -325,12 +325,12 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitTopLevelFunctions (topLevelName: Name): void { + private emitTopLevelFunctions(topLevelName: Name): void { this.emitLine("decodeTopLevel :: ByteString -> Maybe ", topLevelName); this.emitLine("decodeTopLevel = decode"); } - private classPropertyLength (c: ClassType): number { + private classPropertyLength(c: ClassType): number { let counter = 0; this.forEachClassProperty(c, "none", () => { counter += 1; @@ -338,7 +338,7 @@ export class HaskellRenderer extends ConvenienceRenderer { return counter; } - private emitClassEncoderInstance (c: ClassType, className: Name): void { + private emitClassEncoderInstance(c: ClassType, className: Name): void { let classProperties: Array = []; this.forEachClassProperty(c, "none", name => { classProperties.push(" "); @@ -356,7 +356,7 @@ export class HaskellRenderer extends ConvenienceRenderer { this.emitLine("object"); let onFirst = true; this.forEachClassProperty(c, "none", (name, jsonName) => { - this.emitLine(onFirst ? "[ " : ", ", "\"", stringEscape(jsonName), "\" .= ", name, className); + this.emitLine(onFirst ? "[ " : ", ", '"', stringEscape(jsonName), '" .= ', name, className); onFirst = false; }); if (onFirst) { @@ -369,7 +369,7 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitClassDecoderInstance (c: ClassType, className: Name): void { + private emitClassDecoderInstance(c: ClassType, className: Name): void { this.emitLine("instance FromJSON ", className, " where"); this.indent(() => { @@ -381,7 +381,7 @@ export class HaskellRenderer extends ConvenienceRenderer { let onFirst = true; this.forEachClassProperty(c, "none", (_, jsonName, p) => { const operator = p.isOptional ? ".:?" : ".:"; - this.emitLine(onFirst ? "<$> " : "<*> ", "v ", operator, " \"", stringEscape(jsonName), "\""); + this.emitLine(onFirst ? "<$> " : "<*> ", "v ", operator, ' "', stringEscape(jsonName), '"'); onFirst = false; }); }); @@ -389,43 +389,43 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitClassFunctions (c: ClassType, className: Name): void { + private emitClassFunctions(c: ClassType, className: Name): void { this.emitClassEncoderInstance(c, className); this.ensureBlankLine(); this.emitClassDecoderInstance(c, className); } - private emitEnumEncoderInstance (e: EnumType, enumName: Name): void { + private emitEnumEncoderInstance(e: EnumType, enumName: Name): void { this.emitLine("instance ToJSON ", enumName, " where"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("toJSON ", name, enumName, " = \"", stringEscape(jsonName), "\""); + this.emitLine("toJSON ", name, enumName, ' = "', stringEscape(jsonName), '"'); }); }); } - private emitEnumDecoderInstance (e: EnumType, enumName: Name): void { + private emitEnumDecoderInstance(e: EnumType, enumName: Name): void { this.emitLine("instance FromJSON ", enumName, " where"); this.indent(() => { - this.emitLine("parseJSON = withText \"", enumName, "\" parseText"); + this.emitLine('parseJSON = withText "', enumName, '" parseText'); this.indent(() => { this.emitLine("where"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("parseText \"", stringEscape(jsonName), "\" = return ", name, enumName); + this.emitLine('parseText "', stringEscape(jsonName), '" = return ', name, enumName); }); }); }); }); } - private emitEnumFunctions (e: EnumType, enumName: Name): void { + private emitEnumFunctions(e: EnumType, enumName: Name): void { this.emitEnumEncoderInstance(e, enumName); this.ensureBlankLine(); this.emitEnumDecoderInstance(e, enumName); } - private emitUnionEncoderInstance (u: UnionType, unionName: Name): void { + private emitUnionEncoderInstance(u: UnionType, unionName: Name): void { this.emitLine("instance ToJSON ", unionName, " where"); this.indent(() => { this.forEachUnionMember(u, null, "none", null, (constructor, t) => { @@ -438,7 +438,7 @@ export class HaskellRenderer extends ConvenienceRenderer { }); } - private emitUnionDecoderInstance (u: UnionType, unionName: Name): void { + private emitUnionDecoderInstance(u: UnionType, unionName: Name): void { this.emitLine("instance FromJSON ", unionName, " where"); this.indent(() => { this.forEachUnionMember(u, null, "none", null, (constructor, t) => { @@ -450,24 +450,24 @@ export class HaskellRenderer extends ConvenienceRenderer { this.encoderNameForType(t).source, " _) = (fmap ", constructor, - " . parseJSON) xs", + " . parseJSON) xs" ); } }); }); } - private emitUnionFunctions (u: UnionType, unionName: Name): void { + private emitUnionFunctions(u: UnionType, unionName: Name): void { this.emitUnionEncoderInstance(u, unionName); this.ensureBlankLine(); this.emitUnionDecoderInstance(u, unionName); } - private emitLanguageExtensions (ext: string): void { + private emitLanguageExtensions(ext: string): void { this.emitLine(`{-# LANGUAGE ${ext} #-}`); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { const exports: Sourcelike[] = []; this.forEachTopLevel("none", (_, name) => { exports.push([name, " (..)"]); @@ -512,25 +512,25 @@ import Data.Text (Text)`); this.forEachTopLevel( "leading-and-interposing", (t: Type, topLevelName: Name) => this.emitTopLevelDefinition(t, topLevelName), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassDefinition(c, className), (e: EnumType, enumName: Name) => this.emitEnumDefinition(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName), + (u: UnionType, unionName: Name) => this.emitUnionDefinition(u, unionName) ); this.forEachTopLevel("leading-and-interposing", (_: Type, topLevelName: Name) => - this.emitTopLevelFunctions(topLevelName), + this.emitTopLevelFunctions(topLevelName) ); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassFunctions(c, className), (e: EnumType, enumName: Name) => this.emitEnumFunctions(e, enumName), - (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName), + (u: UnionType, unionName: Name) => this.emitUnionFunctions(u, unionName) ); if (this._options.justTypes) return; diff --git a/packages/quicktype-core/src/language/JSONSchema.ts b/packages/quicktype-core/src/language/JSONSchema.ts index c18d6c744..612bd7310 100644 --- a/packages/quicktype-core/src/language/JSONSchema.ts +++ b/packages/quicktype-core/src/language/JSONSchema.ts @@ -1,7 +1,7 @@ import { mapFirst, iterableFirst } from "collection-utils"; import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type UnionType, type EnumType, type ObjectType} from "../Type"; +import { type Type, type UnionType, type EnumType, type ObjectType } from "../Type"; import { transformedStringTypeTargetTypeKindsMap } from "../Type"; import { matchTypeExhaustive } from "../TypeUtils"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; @@ -12,39 +12,39 @@ import { splitIntoWords, combineWords, firstUpperWordStyle, - allUpperWordStyle, + allUpperWordStyle } from "../support/Strings"; import { defined, panic } from "../support/Support"; -import { type StringTypeMapping} from "../TypeBuilder"; +import { type StringTypeMapping } from "../TypeBuilder"; import { getNoStringTypeMapping } from "../TypeBuilder"; import { addDescriptionToSchema } from "../attributes/Description"; import { type Option } from "../RendererOptions"; import { type RenderContext } from "../Renderer"; export class JSONSchemaTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("JSON Schema", ["schema", "json-schema"], "schema"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return []; } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { return getNoStringTypeMapping(); } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsFullObjectType (): boolean { + public get supportsFullObjectType(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - _untypedOptionValues: { [name: string]: any, }, + _untypedOptionValues: { [name: string]: any } ): JSONSchemaRenderer { return new JSONSchemaRenderer(this, renderContext); } @@ -54,7 +54,7 @@ const namingFunction = funPrefixNamer("namer", jsonNameStyle); const legalizeName = legalizeCharacters(cp => cp >= 32 && cp < 128 && cp !== 0x2f /* slash */); -function jsonNameStyle (original: string): string { +function jsonNameStyle(original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -64,36 +64,36 @@ function jsonNameStyle (original: string): string { allUpperWordStyle, allUpperWordStyle, "", - _ => true, + _ => true ); } interface Schema { - [name: string]: any; + [name: string]: any; } export class JSONSchemaRenderer extends ConvenienceRenderer { - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return namingFunction; } - protected namerForObjectProperty (): null { + protected namerForObjectProperty(): null { return null; } - protected makeUnionMemberNamer (): null { + protected makeUnionMemberNamer(): null { return null; } - protected makeEnumCaseNamer (): null { + protected makeEnumCaseNamer(): null { return null; } - private nameForType (t: Type): string { + private nameForType(t: Type): string { return defined(this.names.get(this.nameForNamedType(t))); } - private makeOneOf (types: ReadonlySet): Schema { + private makeOneOf(types: ReadonlySet): Schema { const first = iterableFirst(types); if (first === undefined) { return panic("Must have at least one type for oneOf"); @@ -106,19 +106,19 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { return { anyOf: Array.from(types).map((t: Type) => this.schemaForType(t)) }; } - private makeRef (t: Type): Schema { + private makeRef(t: Type): Schema { return { $ref: `#/definitions/${this.nameForType(t)}` }; } - private addAttributesToSchema (t: Type, schema: Schema): void { + private addAttributesToSchema(t: Type, schema: Schema): void { const attributes = this.typeGraph.attributeStore.attributesForType(t); for (const [kind, attr] of attributes) { kind.addToSchema(schema, t, attr); } } - private schemaForType (t: Type): Schema { - const schema = matchTypeExhaustive<{ [name: string]: any, }>( + private schemaForType(t: Type): Schema { + const schema = matchTypeExhaustive<{ [name: string]: any }>( t, _noneType => { return panic("none type should have been replaced"); @@ -148,7 +148,7 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { } return { type: "string", format: target.jsonSchema }; - }, + } ); if (schema.$ref === undefined) { this.addAttributesToSchema(t, schema); @@ -157,7 +157,7 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { return schema; } - private definitionForObject (o: ObjectType, title: string | undefined): Schema { + private definitionForObject(o: ObjectType, title: string | undefined): Schema { let properties: Schema | undefined; let required: string[] | undefined; if (o.getProperties().size === 0) { @@ -189,13 +189,13 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { additionalProperties, properties, required, - title, + title }; this.addAttributesToSchema(o, schema); return schema; } - private definitionForUnion (u: UnionType, title?: string): Schema { + private definitionForUnion(u: UnionType, title?: string): Schema { const oneOf = this.makeOneOf(u.sortedMembers); if (title !== undefined) { oneOf.title = title; @@ -205,17 +205,17 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { return oneOf; } - private definitionForEnum (e: EnumType, title: string): Schema { + private definitionForEnum(e: EnumType, title: string): Schema { const schema = { type: "string", enum: Array.from(e.cases), title }; this.addAttributesToSchema(e, schema); return schema; } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { // FIXME: Find a good way to do multiple top-levels. Maybe multiple files? const topLevelType = this.topLevels.size === 1 ? this.schemaForType(defined(mapFirst(this.topLevels))) : {}; const schema = Object.assign({ $schema: "http://json-schema.org/draft-06/schema#" }, topLevelType); - const definitions: { [name: string]: Schema, } = {}; + const definitions: { [name: string]: Schema } = {}; this.forEachObject("none", (o: ObjectType, name: Name) => { const title = defined(this.names.get(name)); definitions[title] = this.definitionForObject(o, title); diff --git a/packages/quicktype-core/src/language/Java.ts b/packages/quicktype-core/src/language/Java.ts index a4cc006d1..25b975ad2 100644 --- a/packages/quicktype-core/src/language/Java.ts +++ b/packages/quicktype-core/src/language/Java.ts @@ -4,7 +4,7 @@ import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { type Name, type Namer } from "../Naming"; import { DependencyName, funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { BooleanOption, EnumOption, getOptionValues, StringOption } from "../RendererOptions"; import { type Sourcelike } from "../Source"; import { maybeAnnotated } from "../Source"; @@ -22,11 +22,11 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters, + utf16LegalizeCharacters } from "../support/Strings"; import { assert, assertNever, defined, panic } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type Type, type TypeKind} from "../Type"; +import { type ClassProperty, type Type, type TypeKind } from "../Type"; import { ArrayType, ClassType, EnumType, MapType, UnionType } from "../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; import { type StringTypeMapping, type TransformedStringTypeKind, type PrimitiveStringTypeKind } from ".."; @@ -37,9 +37,9 @@ export const javaOptions = { "Use T[] or List", [ ["array", false], - ["list", true], + ["list", true] ], - "array", + "array" ), justTypes: new BooleanOption("just-types", "Plain types only", false), dateTimeProvider: new EnumOption( @@ -47,23 +47,23 @@ export const javaOptions = { "Date time provider type", [ ["java8", "java8"], - ["legacy", "legacy"], + ["legacy", "legacy"] ], - "java8", + "java8" ), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), // FIXME: Do this via a configurable named eventually. packageName: new StringOption("package", "Generated package name", "NAME", "io.quicktype"), lombok: new BooleanOption("lombok", "Use lombok", false, "primary"), - lombokCopyAnnotations: new BooleanOption("lombok-copy-annotations", "Copy accessor annotations", true, "secondary"), + lombokCopyAnnotations: new BooleanOption("lombok-copy-annotations", "Copy accessor annotations", true, "secondary") }; export class JavaTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Java", ["java"], "java"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ javaOptions.useList, javaOptions.justTypes, @@ -71,15 +71,15 @@ export class JavaTargetLanguage extends TargetLanguage { javaOptions.acronymStyle, javaOptions.packageName, javaOptions.lombok, - javaOptions.lombokCopyAnnotations, + javaOptions.lombokCopyAnnotations ]; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): JavaRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): JavaRenderer { const options = getOptionValues(javaOptions, untypedOptionValues); if (options.justTypes) { return new JavaRenderer(this, renderContext, options); @@ -88,7 +88,7 @@ export class JavaTargetLanguage extends TargetLanguage { return new JacksonRenderer(this, renderContext, options); } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date"); mapping.set("time", "time"); @@ -165,27 +165,27 @@ const javaKeywords = [ "while", "null", "false", - "true", + "true" ]; export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); -function isStartCharacter (codePoint: number): boolean { +function isStartCharacter(codePoint: number): boolean { if (codePoint === 0x5f) return true; // underscore return isAscii(codePoint) && isLetter(codePoint); } -function isPartCharacter (codePoint: number): boolean { - return isStartCharacter(codePoint) || isAscii(codePoint) && isDigit(codePoint); +function isPartCharacter(codePoint: number): boolean { + return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); -export function javaNameStyle ( +export function javaNameStyle( startWithUpper: boolean, upperUnderscore: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle, + acronymsStyle: (s: string) => string = allUpperWordStyle ): string { const words = splitIntoWords(original); return combineWords( @@ -196,39 +196,39 @@ export function javaNameStyle ( upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, upperUnderscore ? "_" : "", - isStartCharacter, + isStartCharacter ); } abstract class JavaDateTimeProvider { - constructor ( + public constructor( protected readonly _renderer: JavaRenderer, - protected readonly _className: string, + protected readonly _className: string ) {} - abstract keywords: string[]; + public abstract keywords: string[]; - abstract dateTimeImports: string[]; + public abstract dateTimeImports: string[]; - abstract dateImports: string[]; + public abstract dateImports: string[]; - abstract timeImports: string[]; + public abstract timeImports: string[]; - abstract converterImports: string[]; + public abstract converterImports: string[]; - abstract dateTimeType: string; + public abstract dateTimeType: string; - abstract dateType: string; + public abstract dateType: string; - abstract timeType: string; + public abstract timeType: string; - abstract dateTimeJacksonAnnotations: string[]; + public abstract dateTimeJacksonAnnotations: string[]; - abstract dateJacksonAnnotations: string[]; + public abstract dateJacksonAnnotations: string[]; - abstract timeJacksonAnnotations: string[]; + public abstract timeJacksonAnnotations: string[]; - abstract emitDateTimeConverters (): void; + public abstract emitDateTimeConverters(): void; public shouldEmitDateTimeConverter = true; @@ -236,17 +236,17 @@ abstract class JavaDateTimeProvider { public shouldEmitDateConverter = true; - abstract convertStringToDateTime (variable: Sourcelike): Sourcelike; - abstract convertStringToTime (variable: Sourcelike): Sourcelike; - abstract convertStringToDate (variable: Sourcelike): Sourcelike; + public abstract convertStringToDateTime(variable: Sourcelike): Sourcelike; + public abstract convertStringToTime(variable: Sourcelike): Sourcelike; + public abstract convertStringToDate(variable: Sourcelike): Sourcelike; - abstract convertDateTimeToString (variable: Sourcelike): Sourcelike; - abstract convertTimeToString (variable: Sourcelike): Sourcelike; - abstract convertDateToString (variable: Sourcelike): Sourcelike; + public abstract convertDateTimeToString(variable: Sourcelike): Sourcelike; + public abstract convertTimeToString(variable: Sourcelike): Sourcelike; + public abstract convertDateToString(variable: Sourcelike): Sourcelike; } class Java8DateTimeProvider extends JavaDateTimeProvider { - keywords = [ + public keywords = [ "LocalDate", "OffsetDateTime", "OffsetTime", @@ -254,16 +254,16 @@ class Java8DateTimeProvider extends JavaDateTimeProvider { "ZonedDateTime", "DateTimeFormatter", "DateTimeFormatterBuilder", - "ChronoField", + "ChronoField" ]; - dateTimeImports: string[] = ["java.time.OffsetDateTime"]; + public dateTimeImports: string[] = ["java.time.OffsetDateTime"]; - dateImports: string[] = ["java.time.LocalDate"]; + public dateImports: string[] = ["java.time.LocalDate"]; - timeImports: string[] = ["java.time.OffsetTime"]; + public timeImports: string[] = ["java.time.OffsetTime"]; - converterImports: string[] = [ + public converterImports: string[] = [ "java.time.LocalDate", "java.time.OffsetDateTime", "java.time.OffsetTime", @@ -271,48 +271,48 @@ class Java8DateTimeProvider extends JavaDateTimeProvider { "java.time.ZonedDateTime", "java.time.format.DateTimeFormatter", "java.time.format.DateTimeFormatterBuilder", - "java.time.temporal.ChronoField", + "java.time.temporal.ChronoField" ]; - dateTimeType = "OffsetDateTime"; + public dateTimeType = "OffsetDateTime"; - dateType = "LocalDate"; + public dateType = "LocalDate"; - timeType = "OffsetTime"; + public timeType = "OffsetTime"; - dateTimeJacksonAnnotations: string[] = []; + public dateTimeJacksonAnnotations: string[] = []; - dateJacksonAnnotations: string[] = []; + public dateJacksonAnnotations: string[] = []; - timeJacksonAnnotations: string[] = []; + public timeJacksonAnnotations: string[] = []; - emitDateTimeConverters (): void { + public emitDateTimeConverters(): void { this._renderer.ensureBlankLine(); this._renderer.emitLine( - "private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()", + "private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()" ); this._renderer.indent(() => this._renderer.indent(() => { this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_DATE_TIME)"); this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)"); this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_INSTANT)"); - this._renderer.emitLine(".appendOptional(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.SX\"))"); - this._renderer.emitLine(".appendOptional(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ssX\"))"); - this._renderer.emitLine(".appendOptional(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\"))"); + this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SX"))'); + this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX"))'); + this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))'); this._renderer.emitLine(".toFormatter()"); this._renderer.emitLine(".withZone(ZoneOffset.UTC);"); - }), + }) ); this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static OffsetDateTime parseDateTimeString(String str)", () => { this._renderer.emitLine( - "return ZonedDateTime.from(Converter.DATE_TIME_FORMATTER.parse(str)).toOffsetDateTime();", + "return ZonedDateTime.from(Converter.DATE_TIME_FORMATTER.parse(str)).toOffsetDateTime();" ); }); this._renderer.ensureBlankLine(); this._renderer.emitLine( - "private static final DateTimeFormatter TIME_FORMATTER = new DateTimeFormatterBuilder()", + "private static final DateTimeFormatter TIME_FORMATTER = new DateTimeFormatterBuilder()" ); this._renderer.indent(() => this._renderer.indent(() => { @@ -323,65 +323,71 @@ class Java8DateTimeProvider extends JavaDateTimeProvider { this._renderer.emitLine(".parseDefaulting(ChronoField.DAY_OF_MONTH, 1)"); this._renderer.emitLine(".toFormatter()"); this._renderer.emitLine(".withZone(ZoneOffset.UTC);"); - }), + }) ); this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static OffsetTime parseTimeString(String str)", () => { this._renderer.emitLine( - "return ZonedDateTime.from(Converter.TIME_FORMATTER.parse(str)).toOffsetDateTime().toOffsetTime();", + "return ZonedDateTime.from(Converter.TIME_FORMATTER.parse(str)).toOffsetDateTime().toOffsetTime();" ); }); } - convertStringToDateTime (variable: Sourcelike): Sourcelike { + public convertStringToDateTime(variable: Sourcelike): Sourcelike { return [this._className, ".parseDateTimeString(", variable, ")"]; } - convertStringToTime (variable: Sourcelike): Sourcelike { + public convertStringToTime(variable: Sourcelike): Sourcelike { return [this._className, ".parseTimeString(", variable, ")"]; } - convertStringToDate (variable: Sourcelike): Sourcelike { + public convertStringToDate(variable: Sourcelike): Sourcelike { return ["LocalDate.parse(", variable, ")"]; } - convertDateTimeToString (variable: Sourcelike): Sourcelike { + public convertDateTimeToString(variable: Sourcelike): Sourcelike { return [variable, ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)"]; } - convertTimeToString (variable: Sourcelike): Sourcelike { + public convertTimeToString(variable: Sourcelike): Sourcelike { return [variable, ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_TIME)"]; } - convertDateToString (variable: Sourcelike): Sourcelike { + public convertDateToString(variable: Sourcelike): Sourcelike { return [variable, ".format(java.time.format.DateTimeFormatter.ISO_DATE)"]; } } class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { - keywords = ["SimpleDateFormat", "Date"]; + public keywords = ["SimpleDateFormat", "Date"]; - dateTimeImports: string[] = ["java.util.Date"]; + public dateTimeImports: string[] = ["java.util.Date"]; - dateImports: string[] = ["java.util.Date"]; + public dateImports: string[] = ["java.util.Date"]; - timeImports: string[] = ["java.util.Date"]; + public timeImports: string[] = ["java.util.Date"]; - converterImports: string[] = ["java.util.Date", "java.text.SimpleDateFormat"]; + public converterImports: string[] = ["java.util.Date", "java.text.SimpleDateFormat"]; - dateTimeType = "Date"; + public dateTimeType = "Date"; - dateType = "Date"; + public dateType = "Date"; - timeType = "Date"; + public timeType = "Date"; - dateTimeJacksonAnnotations: string[] = ["@JsonFormat(pattern = \"yyyy-MM-dd'T'HH:mm:ssX\", timezone = \"UTC\")"]; + public dateTimeJacksonAnnotations: string[] = [ + '@JsonFormat(pattern = "yyyy-MM-dd\'T\'HH:mm:ssX", timezone = "UTC")' + ]; + + public dateJacksonAnnotations: string[] = ['@JsonFormat(pattern = "yyyy-MM-dd")']; + + public timeJacksonAnnotations: string[] = ['@JsonFormat(pattern = "HH:mm:ssX", timezone = "UTC")']; - dateJacksonAnnotations: string[] = ["@JsonFormat(pattern = \"yyyy-MM-dd\")"]; + public shouldEmitTimeConverter = false; - timeJacksonAnnotations: string[] = ["@JsonFormat(pattern = \"HH:mm:ssX\", timezone = \"UTC\")"]; + public shouldEmitDateConverter = false; - emitDateTimeConverters (): void { + public emitDateTimeConverters(): void { this._renderer.ensureBlankLine(); this._renderer.emitLine("private static final String[] DATE_TIME_FORMATS = {"); this._renderer.indent(() => @@ -390,16 +396,16 @@ class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ss.S\","); this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ssX\","); this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ss\","); - this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ss.SX\","); - this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ss.S\","); - this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ssX\","); - this._renderer.emitLine("\"yyyy-MM-dd HH:mm:ss\","); - this._renderer.emitLine("\"HH:mm:ss.SZ\","); - this._renderer.emitLine("\"HH:mm:ss.S\","); - this._renderer.emitLine("\"HH:mm:ssZ\","); - this._renderer.emitLine("\"HH:mm:ss\","); - this._renderer.emitLine("\"yyyy-MM-dd\","); - }), + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss.SX",'); + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss.S",'); + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ssX",'); + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss",'); + this._renderer.emitLine('"HH:mm:ss.SZ",'); + this._renderer.emitLine('"HH:mm:ss.S",'); + this._renderer.emitLine('"HH:mm:ssZ",'); + this._renderer.emitLine('"HH:mm:ss",'); + this._renderer.emitLine('"yyyy-MM-dd",'); + }) ); this._renderer.emitLine("};"); this._renderer.ensureBlankLine(); @@ -419,40 +425,36 @@ class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static String serializeDate(Date datetime)", () => { - this._renderer.emitLine("return new SimpleDateFormat(\"yyyy-MM-dd\").format(datetime);"); + this._renderer.emitLine('return new SimpleDateFormat("yyyy-MM-dd").format(datetime);'); }); this._renderer.ensureBlankLine(); this._renderer.emitBlock("public static String serializeTime(Date datetime)", () => { - this._renderer.emitLine("return new SimpleDateFormat(\"hh:mm:ssZ\").format(datetime);"); + this._renderer.emitLine('return new SimpleDateFormat("hh:mm:ssZ").format(datetime);'); }); } - shouldEmitTimeConverter = false; - - shouldEmitDateConverter = false; - - convertStringToDateTime (variable: Sourcelike): Sourcelike { + public convertStringToDateTime(variable: Sourcelike): Sourcelike { return [this._className, ".parseAllDateTimeString(", variable, ")"]; } - convertStringToTime (variable: Sourcelike): Sourcelike { + public convertStringToTime(variable: Sourcelike): Sourcelike { return [this._className, ".parseAllDateTimeString(", variable, ")"]; } - convertStringToDate (variable: Sourcelike): Sourcelike { + public convertStringToDate(variable: Sourcelike): Sourcelike { return [this._className, ".parseAllDateTimeString(", variable, ")"]; } - convertDateTimeToString (variable: Sourcelike): Sourcelike { + public convertDateTimeToString(variable: Sourcelike): Sourcelike { return [this._className, ".serializeDateTime(", variable, ")"]; } - convertTimeToString (variable: Sourcelike): Sourcelike { + public convertTimeToString(variable: Sourcelike): Sourcelike { return [this._className, ".serializeTime(", variable, ")"]; } - convertDateToString (variable: Sourcelike): Sourcelike { + public convertDateToString(variable: Sourcelike): Sourcelike { return [this._className, ".serializeDate(", variable, ")"]; } } @@ -470,10 +472,10 @@ export class JavaRenderer extends ConvenienceRenderer { protected readonly _converterKeywords: string[] = []; - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues, + protected readonly _options: OptionValues ) { super(targetLanguage, renderContext); @@ -488,95 +490,95 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { const keywords = [ ...javaKeywords, ...this._converterKeywords, this._converterClassname, - ...this._dateTimeProvider.keywords, + ...this._dateTimeProvider.keywords ]; return keywords; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return this.getNameStyling("typeNamingFunction"); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return this.getNameStyling("enumCaseNamingFunction"); } - protected unionNeedsName (u: UnionType): boolean { + protected unionNeedsName(u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { // If the top-level type doesn't contain any classes or unions // we have to define a class just for the `FromJson` method, in // emitFromJsonForTopLevel. return directlyReachableSingleNamedType(type); } - protected makeNamesForPropertyGetterAndSetter ( + protected makeNamesForPropertyGetterAndSetter( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name, + name: Name ): [Name, Name] { const getterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `get_${lookup(name)}`, + lookup => `get_${lookup(name)}` ); const setterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `set_${lookup(name)}`, + lookup => `set_${lookup(name)}` ); return [getterName, setterName]; } - protected makePropertyDependencyNames ( + protected makePropertyDependencyNames( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name, + name: Name ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return getterAndSetterNames; } - private getNameStyling (convention: string): Namer { - const styling: { [key: string]: Namer, } = { + private getNameStyling(convention: string): Namer { + const styling: { [key: string]: Namer } = { typeNamingFunction: funPrefixNamer("types", n => - javaNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)), + javaNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)) ), propertyNamingFunction: funPrefixNamer("properties", n => - javaNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)), + javaNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)) ), enumCaseNamingFunction: funPrefixNamer("enum-cases", n => - javaNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)), - ), + javaNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)) + ) }; return styling[convention]; } - protected fieldOrMethodName (methodName: string, topLevelName: Name): Sourcelike { + protected fieldOrMethodName(methodName: string, topLevelName: Name): Sourcelike { if (this.topLevels.size === 1) { return methodName; } @@ -584,7 +586,7 @@ export class JavaRenderer extends ConvenienceRenderer { return [topLevelName, capitalize(methodName)]; } - protected methodName (prefix: string, suffix: string, topLevelName: Name): Sourcelike { + protected methodName(prefix: string, suffix: string, topLevelName: Name): Sourcelike { if (this.topLevels.size === 1) { return [prefix, suffix]; } @@ -592,23 +594,23 @@ export class JavaRenderer extends ConvenienceRenderer { return [prefix, topLevelName, suffix]; } - protected decoderName (topLevelName: Name): Sourcelike { + protected decoderName(topLevelName: Name): Sourcelike { return this.fieldOrMethodName("fromJsonString", topLevelName); } - protected encoderName (topLevelName: Name): Sourcelike { + protected encoderName(topLevelName: Name): Sourcelike { return this.fieldOrMethodName("toJsonString", topLevelName); } - protected readerGetterName (topLevelName: Name): Sourcelike { + protected readerGetterName(topLevelName: Name): Sourcelike { return this.methodName("get", "ObjectReader", topLevelName); } - protected writerGetterName (topLevelName: Name): Sourcelike { + protected writerGetterName(topLevelName: Name): Sourcelike { return this.methodName("get", "ObjectWriter", topLevelName); } - protected startFile (basename: Sourcelike): void { + protected startFile(basename: Sourcelike): void { assert(this._currentFilename === undefined, "Previous file wasn't finished"); // FIXME: The filenames should actually be Sourcelikes, too this._currentFilename = `${this.sourcelikeToString(basename)}.java`; @@ -621,12 +623,12 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected finishFile (): void { + protected finishFile(): void { super.finishFile(defined(this._currentFilename)); this._currentFilename = undefined; } - protected emitPackageAndImports (imports: string[]): void { + protected emitPackageAndImports(imports: string[]): void { this.emitLine("package ", this._options.packageName, ";"); this.ensureBlankLine(); for (const pkg of imports) { @@ -634,23 +636,23 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected emitFileHeader (fileName: Sourcelike, imports: string[]): void { + protected emitFileHeader(fileName: Sourcelike, imports: string[]): void { this.startFile(fileName); this.emitPackageAndImports(imports); this.ensureBlankLine(); } - public emitDescriptionBlock (lines: Sourcelike[]): void { + public emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - public emitBlock (line: Sourcelike, f: () => void): void { + public emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - public emitTryCatch (main: () => void, handler: () => void, exception = "Exception") { + public emitTryCatch(main: () => void, handler: () => void, exception = "Exception") { this.emitLine("try {"); this.indent(main); this.emitLine("} catch (", exception, " ex) {"); @@ -658,18 +660,18 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitLine("}"); } - public emitIgnoredTryCatchBlock (f: () => void) { + public emitIgnoredTryCatchBlock(f: () => void) { this.emitTryCatch(f, () => this.emitLine("// Ignored")); } - protected javaType (reference: boolean, t: Type, withIssues = false): Sourcelike { + protected javaType(reference: boolean, t: Type, withIssues = false): Sourcelike { return matchType( t, _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "Object"), _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, "Object"), - _boolType => reference ? "Boolean" : "boolean", - _integerType => reference ? "Long" : "long", - _doubleType => reference ? "Double" : "double", + _boolType => (reference ? "Boolean" : "boolean"), + _integerType => (reference ? "Long" : "long"), + _doubleType => (reference ? "Double" : "double"), _stringType => "String", arrayType => { if (this._options.useList) { @@ -704,11 +706,11 @@ export class JavaRenderer extends ConvenienceRenderer { } return "String"; - }, + } ); } - protected javaImport (t: Type): string[] { + protected javaImport(t: Type): string[] { return matchType( t, _anyType => [], @@ -750,11 +752,11 @@ export class JavaRenderer extends ConvenienceRenderer { } return []; - }, + } ); } - protected javaTypeWithoutGenerics (reference: boolean, t: Type): Sourcelike { + protected javaTypeWithoutGenerics(reference: boolean, t: Type): Sourcelike { if (t instanceof ArrayType) { if (this._options.useList) { return ["List"]; @@ -772,24 +774,24 @@ export class JavaRenderer extends ConvenienceRenderer { } } - protected emitClassAttributes (_c: ClassType, _className: Name): void { + protected emitClassAttributes(_c: ClassType, _className: Name): void { if (this._options.lombok) { this.emitLine("@lombok.Data"); } } - protected annotationsForAccessor ( + protected annotationsForAccessor( _c: ClassType, _className: Name, _propertyName: Name, _jsonName: string, _p: ClassProperty, - _isSetter: boolean, + _isSetter: boolean ): string[] { return []; } - protected importsForType (t: ClassType | UnionType | EnumType): string[] { + protected importsForType(t: ClassType | UnionType | EnumType): string[] { if (t instanceof ClassType) { return []; } @@ -805,7 +807,7 @@ export class JavaRenderer extends ConvenienceRenderer { return assertNever(t); } - protected importsForClass (c: ClassType): string[] { + protected importsForClass(c: ClassType): string[] { const imports: string[] = []; this.forEachClassProperty(c, "none", (_name, _jsonName, p) => { this.javaImport(p.type).forEach(imp => imports.push(imp)); @@ -814,7 +816,7 @@ export class JavaRenderer extends ConvenienceRenderer { return [...new Set(imports)]; } - protected importsForUnionMembers (u: UnionType): string[] { + protected importsForUnionMembers(u: UnionType): string[] { const imports: string[] = []; const [, nonNulls] = removeNullFromUnion(u); this.forEachUnionMember(u, nonNulls, "none", null, (_fieldName, t) => { @@ -824,7 +826,7 @@ export class JavaRenderer extends ConvenienceRenderer { return [...new Set(imports)]; } - protected emitClassDefinition (c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name): void { let imports = [...this.importsForType(c), ...this.importsForClass(c)]; this.emitFileHeader(className, imports); @@ -852,11 +854,11 @@ export class JavaRenderer extends ConvenienceRenderer { const [getterName, setterName] = defined(this._gettersAndSettersForPropertyName.get(name)); const rendered = this.javaType(false, p.type); this.annotationsForAccessor(c, className, name, jsonName, p, false).forEach(annotation => - this.emitLine(annotation), + this.emitLine(annotation) ); this.emitLine("public ", rendered, " ", getterName, "() { return ", name, "; }"); this.annotationsForAccessor(c, className, name, jsonName, p, true).forEach(annotation => - this.emitLine(annotation), + this.emitLine(annotation) ); this.emitLine("public void ", setterName, "(", rendered, " value) { this.", name, " = value; }"); }); @@ -865,22 +867,22 @@ export class JavaRenderer extends ConvenienceRenderer { this.finishFile(); } - protected unionField (u: UnionType, t: Type, withIssues = false): { fieldName: Sourcelike, fieldType: Sourcelike, } { + protected unionField(u: UnionType, t: Type, withIssues = false): { fieldName: Sourcelike; fieldType: Sourcelike } { const fieldType = this.javaType(true, t, withIssues); // FIXME: "Value" should be part of the name. const fieldName = [this.nameForUnionMember(u, t), "Value"]; return { fieldType, fieldName }; } - protected emitUnionAttributes (_u: UnionType, _unionName: Name): void { + protected emitUnionAttributes(_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionSerializer (_u: UnionType, _unionName: Name): void { + protected emitUnionSerializer(_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionDefinition (u: UnionType, unionName: Name): void { + protected emitUnionDefinition(u: UnionType, unionName: Name): void { const imports = [...this.importsForType(u), ...this.importsForUnionMembers(u)]; this.emitFileHeader(unionName, imports); @@ -899,15 +901,15 @@ export class JavaRenderer extends ConvenienceRenderer { this.finishFile(); } - protected emitEnumSerializationAttributes (_e: EnumType) { + protected emitEnumSerializationAttributes(_e: EnumType) { // Empty } - protected emitEnumDeserializationAttributes (_e: EnumType) { + protected emitEnumDeserializationAttributes(_e: EnumType) { // Empty } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitFileHeader(enumName, this.importsForType(e)); this.emitDescription(this.descriptionForType(e)); const caseNames: Sourcelike[] = []; @@ -925,7 +927,7 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitLine("switch (this) {"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("case ", name, ": return \"", stringEscape(jsonName), "\";"); + this.emitLine("case ", name, ': return "', stringEscape(jsonName), '";'); }); }); this.emitLine("}"); @@ -936,29 +938,29 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitEnumDeserializationAttributes(e); this.emitBlock(["public static ", enumName, " forValue(String value) throws IOException"], () => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("if (value.equals(\"", stringEscape(jsonName), "\")) return ", name, ";"); + this.emitLine('if (value.equals("', stringEscape(jsonName), '")) return ', name, ";"); }); - this.emitLine("throw new IOException(\"Cannot deserialize ", enumName, "\");"); + this.emitLine('throw new IOException("Cannot deserialize ', enumName, '");'); }); }); this.finishFile(); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.forEachNamedType( "leading-and-interposing", (c: ClassType, n: Name) => this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n), + (u, n) => this.emitUnionDefinition(u, n) ); } } export class JacksonRenderer extends JavaRenderer { - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - options: OptionValues, + options: OptionValues ) { super(targetLanguage, renderContext, options); } @@ -972,27 +974,27 @@ export class JacksonRenderer extends JavaRenderer { "JsonParser", "JsonProcessingException", "DeserializationContext", - "SerializerProvider", + "SerializerProvider" ]; - protected emitClassAttributes (c: ClassType, _className: Name): void { + protected emitClassAttributes(c: ClassType, _className: Name): void { if (c.getProperties().size === 0) this.emitLine("@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.NONE)"); super.emitClassAttributes(c, _className); } - protected annotationsForAccessor ( + protected annotationsForAccessor( _c: ClassType, _className: Name, _propertyName: Name, jsonName: string, p: ClassProperty, - _isSetter: boolean, + _isSetter: boolean ): string[] { const superAnnotations = super.annotationsForAccessor(_c, _className, _propertyName, jsonName, p, _isSetter); - const annotations: string[] = ["@JsonProperty(\"" + stringEscape(jsonName) + "\")"]; + const annotations: string[] = ['@JsonProperty("' + stringEscape(jsonName) + '")']; switch (p.type.kind) { case "date-time": @@ -1011,7 +1013,7 @@ export class JacksonRenderer extends JavaRenderer { return [...superAnnotations, ...annotations]; } - protected importsForType (t: ClassType | UnionType | EnumType): string[] { + protected importsForType(t: ClassType | UnionType | EnumType): string[] { if (t instanceof ClassType) { const imports = super.importsForType(t); imports.push("com.fasterxml.jackson.annotation.*"); @@ -1024,7 +1026,7 @@ export class JacksonRenderer extends JavaRenderer { "java.io.IOException", "com.fasterxml.jackson.core.*", "com.fasterxml.jackson.databind.*", - "com.fasterxml.jackson.databind.annotation.*", + "com.fasterxml.jackson.databind.annotation.*" ); if (this._options.useList) { imports.push("com.fasterxml.jackson.core.type.*"); @@ -1042,12 +1044,12 @@ export class JacksonRenderer extends JavaRenderer { return assertNever(t); } - protected emitUnionAttributes (_u: UnionType, unionName: Name): void { + protected emitUnionAttributes(_u: UnionType, unionName: Name): void { this.emitLine("@JsonDeserialize(using = ", unionName, ".Deserializer.class)"); this.emitLine("@JsonSerialize(using = ", unionName, ".Serializer.class)"); } - protected emitUnionSerializer (u: UnionType, unionName: Name): void { + protected emitUnionSerializer(u: UnionType, unionName: Name): void { const stringBasedObjects: TypeKind[] = ["uuid", "time", "date", "date-time"]; const tokenCase = (tokenType: string): void => { @@ -1064,7 +1066,7 @@ export class JacksonRenderer extends JavaRenderer { const emitDeserializerCodeForStringObjects = ( fieldName: Sourcelike, kind: TypeKind, - parseFrom: string, + parseFrom: string ): void => { switch (kind) { case "date": @@ -1073,7 +1075,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = ", this._dateTimeProvider.convertStringToDate(parseFrom), - ";", + ";" ); break; @@ -1083,7 +1085,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = ", this._dateTimeProvider.convertStringToTime(parseFrom), - ";", + ";" ); break; @@ -1093,7 +1095,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = ", this._dateTimeProvider.convertStringToDateTime(parseFrom), - ";", + ";" ); break; case "uuid": @@ -1114,7 +1116,7 @@ export class JacksonRenderer extends JavaRenderer { fieldName, " = jsonParser.readValueAs(new TypeReference<", rendered, - ">() {});", + ">() {});" ); } else if (stringBasedObjects.some(stringBasedTypeKind => t.kind === stringBasedTypeKind)) { emitDeserializerCodeForStringObjects(fieldName, t.kind, variableFieldName); @@ -1249,7 +1251,7 @@ export class JacksonRenderer extends JavaRenderer { [ "public ", unionName, - " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException", + " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException" ], () => { this.emitLine(unionName, " value = new ", unionName, "();"); @@ -1262,11 +1264,11 @@ export class JacksonRenderer extends JavaRenderer { emitDeserializer(["START_OBJECT"], "class"); emitDeserializer(["START_OBJECT"], "map"); this.indent(() => - this.emitLine("default: throw new IOException(\"Cannot deserialize ", unionName, "\");"), + this.emitLine('default: throw new IOException("Cannot deserialize ', unionName, '");') ); this.emitLine("}"); this.emitLine("return value;"); - }, + } ); }); this.ensureBlankLine(); @@ -1276,7 +1278,7 @@ export class JacksonRenderer extends JavaRenderer { [ "public void serialize(", unionName, - " obj, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException", + " obj, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException" ], () => { for (const t of nonNulls) { @@ -1286,22 +1288,22 @@ export class JacksonRenderer extends JavaRenderer { if (maybeNull !== null) { this.emitLine("jsonGenerator.writeNull();"); } else { - this.emitLine("throw new IOException(\"", unionName, " must not be null\");"); + this.emitLine('throw new IOException("', unionName, ' must not be null");'); } - }, + } ); }); } - protected emitEnumSerializationAttributes (_e: EnumType) { + protected emitEnumSerializationAttributes(_e: EnumType) { this.emitLine("@JsonValue"); } - protected emitEnumDeserializationAttributes (_e: EnumType) { + protected emitEnumDeserializationAttributes(_e: EnumType) { this.emitLine("@JsonCreator"); } - protected emitOffsetDateTimeConverterModule (): void { + protected emitOffsetDateTimeConverterModule(): void { this.emitLine("SimpleModule module = new SimpleModule();"); if (this._dateTimeProvider.shouldEmitDateTimeConverter) { @@ -1310,7 +1312,7 @@ export class JacksonRenderer extends JavaRenderer { this._dateTimeProvider.dateTimeType, ".class, new JsonDeserializer<", this._dateTimeProvider.dateTimeType, - ">() {", + ">() {" ); this.indent(() => { this.emitLine("@Override"); @@ -1319,12 +1321,12 @@ export class JacksonRenderer extends JavaRenderer { "public ", this._dateTimeProvider.dateTimeType, " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", - "throws IOException, JsonProcessingException", + "throws IOException, JsonProcessingException" ], () => { this.emitLine("String value = jsonParser.getText();"); this.emitLine("return ", this._dateTimeProvider.convertStringToDateTime("value"), ";"); - }, + } ); }); this.emitLine("});"); @@ -1336,7 +1338,7 @@ export class JacksonRenderer extends JavaRenderer { this._dateTimeProvider.timeType, ".class, new JsonDeserializer<", this._dateTimeProvider.timeType, - ">() {", + ">() {" ); this.indent(() => { this.emitLine("@Override"); @@ -1345,12 +1347,12 @@ export class JacksonRenderer extends JavaRenderer { "public ", this._dateTimeProvider.timeType, " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", - "throws IOException, JsonProcessingException", + "throws IOException, JsonProcessingException" ], () => { this.emitLine("String value = jsonParser.getText();"); this.emitLine("return ", this._dateTimeProvider.convertStringToTime("value"), ";"); - }, + } ); }); this.emitLine("});"); @@ -1362,7 +1364,7 @@ export class JacksonRenderer extends JavaRenderer { this._dateTimeProvider.dateType, ".class, new JsonDeserializer<", this._dateTimeProvider.dateType, - ">() {", + ">() {" ); this.indent(() => { this.emitLine("@Override"); @@ -1371,12 +1373,12 @@ export class JacksonRenderer extends JavaRenderer { "public ", this._dateTimeProvider.dateType, " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", - "throws IOException, JsonProcessingException", + "throws IOException, JsonProcessingException" ], () => { this.emitLine("String value = jsonParser.getText();"); this.emitLine("return ", this._dateTimeProvider.convertStringToDate("value"), ";"); - }, + } ); }); this.emitLine("});"); @@ -1385,7 +1387,7 @@ export class JacksonRenderer extends JavaRenderer { this.emitLine("mapper.registerModule(module);"); } - protected emitConverterClass (): void { + protected emitConverterClass(): void { this.startFile(this._converterClassname); this.emitCommentLines([ "To use this code, add the following Maven dependency to your project:", @@ -1397,7 +1399,7 @@ export class JacksonRenderer extends JavaRenderer { : "", "", "Import this package:", - "", + "" ]); this.emitLine("// import ", this._options.packageName, ".Converter;"); this.emitMultiline(`// @@ -1409,7 +1411,7 @@ export class JacksonRenderer extends JavaRenderer { this.javaType(false, t), " data = Converter.", this.decoderName(name), - "(jsonString);", + "(jsonString);" ); }); this.ensureBlankLine(); @@ -1419,7 +1421,7 @@ export class JacksonRenderer extends JavaRenderer { "com.fasterxml.jackson.databind.module.SimpleModule", "com.fasterxml.jackson.core.JsonParser", "com.fasterxml.jackson.core.JsonProcessingException", - "java.util.*", + "java.util.*" ].concat(this._dateTimeProvider.converterImports); this.emitPackageAndImports(imports); this.ensureBlankLine(); @@ -1436,11 +1438,11 @@ export class JacksonRenderer extends JavaRenderer { topLevelTypeRendered, " ", this.decoderName(topLevelName), - "(String json) throws IOException", + "(String json) throws IOException" ], () => { this.emitLine("return ", this.readerGetterName(topLevelName), "().readValue(json);"); - }, + } ); this.ensureBlankLine(); this.emitBlock( @@ -1449,11 +1451,11 @@ export class JacksonRenderer extends JavaRenderer { this.encoderName(topLevelName), "(", topLevelTypeRendered, - " obj) throws JsonProcessingException", + " obj) throws JsonProcessingException" ], () => { this.emitLine("return ", this.writerGetterName(topLevelName), "().writeValueAsString(obj);"); - }, + } ); }); this.forEachTopLevel("leading-and-interposing", (topLevelType, topLevelName) => { @@ -1473,7 +1475,7 @@ export class JacksonRenderer extends JavaRenderer { this.emitOffsetDateTimeConverterModule(); this.emitLine(readerName, " = mapper.readerFor(", renderedForClass, ".class);"); this.emitLine(writerName, " = mapper.writerFor(", renderedForClass, ".class);"); - }, + } ); this.ensureBlankLine(); this.emitBlock(["private static ObjectReader ", this.readerGetterName(topLevelName), "()"], () => { @@ -1482,7 +1484,7 @@ export class JacksonRenderer extends JavaRenderer { readerName, " == null) ", this.methodName("instantiate", "Mapper", topLevelName), - "();", + "();" ); this.emitLine("return ", readerName, ";"); }); @@ -1493,7 +1495,7 @@ export class JacksonRenderer extends JavaRenderer { writerName, " == null) ", this.methodName("instantiate", "Mapper", topLevelName), - "();", + "();" ); this.emitLine("return ", writerName, ";"); }); @@ -1502,7 +1504,7 @@ export class JacksonRenderer extends JavaRenderer { this.finishFile(); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.emitConverterClass(); super.emitSourceStructure(); } diff --git a/packages/quicktype-core/src/language/JavaScript.ts b/packages/quicktype-core/src/language/JavaScript.ts index 1936de7b2..5b1b1b7c8 100644 --- a/packages/quicktype-core/src/language/JavaScript.ts +++ b/packages/quicktype-core/src/language/JavaScript.ts @@ -6,7 +6,7 @@ import { type Type, type ClassProperty, type ClassType, - type ObjectType, + type ObjectType } from "../Type"; import { matchType, directlyReachableSingleNamedType } from "../TypeUtils"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; @@ -20,18 +20,18 @@ import { combineWords, firstUpperWordStyle, camelCase, - allLowerWordStyle, + allLowerWordStyle } from "../support/Strings"; import { panic } from "../support/Support"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { modifySource } from "../Source"; -import { type Namer, type Name} from "../Naming"; +import { type Namer, type Name } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { TargetLanguage } from "../TargetLanguage"; import { type StringTypeMapping } from "../TypeBuilder"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { BooleanOption, getOptionValues, EnumOption } from "../RendererOptions"; import { type RenderContext } from "../Renderer"; import { isES3IdentifierPart, isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; @@ -43,7 +43,7 @@ export const javaScriptOptions = { "runtime-typecheck-ignore-unknown-properties", "Ignore unknown properties when verifying at runtime", false, - "secondary", + "secondary" ), converters: convertersOption(), rawType: new EnumOption<"json" | "any">( @@ -51,11 +51,11 @@ export const javaScriptOptions = { "Type of raw input (json by default)", [ ["json", "json"], - ["any", "any"], + ["any", "any"] ], "json", - "secondary", - ), + "secondary" + ) }; export interface JavaScriptTypeAnnotations { @@ -69,21 +69,21 @@ export interface JavaScriptTypeAnnotations { } export class JavaScriptTargetLanguage extends TargetLanguage { - constructor (displayName = "JavaScript", names: string[] = ["javascript", "js", "jsx"], extension = "js") { + public constructor(displayName = "JavaScript", names: string[] = ["javascript", "js", "jsx"], extension = "js") { super(displayName, names, extension); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ javaScriptOptions.runtimeTypecheck, javaScriptOptions.runtimeTypecheckIgnoreUnknownProperties, javaScriptOptions.acronymStyle, javaScriptOptions.converters, - javaScriptOptions.rawType, + javaScriptOptions.rawType ]; } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); @@ -91,17 +91,17 @@ export class JavaScriptTargetLanguage extends TargetLanguage { return mapping; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsFullObjectType (): boolean { + public get supportsFullObjectType(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): JavaScriptRenderer { return new JavaScriptRenderer(this, renderContext, getOptionValues(javaScriptOptions, untypedOptionValues)); } @@ -112,15 +112,15 @@ export const legalizeName = utf16LegalizeCharacters(isES3IdentifierPart); const identityNamingFunction = funPrefixNamer("properties", s => s); export class JavaScriptRenderer extends ConvenienceRenderer { - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _jsOptions: OptionValues, + private readonly _jsOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected nameStyle (original: string, upper: boolean): string { + protected nameStyle(original: string, upper: boolean): string { const acronyms = acronymStyle(this._jsOptions.acronymStyle); const words = splitIntoWords(original); return combineWords( @@ -131,58 +131,58 @@ export class JavaScriptRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isES3IdentifierStart, + isES3IdentifierStart ); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return identityNamingFunction; } - protected makeUnionMemberNamer (): null { + protected makeUnionMemberNamer(): null { return null; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, true)); } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { return directlyReachableSingleNamedType(type); } - protected makeNameForProperty ( + protected makeNameForProperty( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - _assignedName: string | undefined, + _assignedName: string | undefined ): Name | undefined { // Ignore the assigned name return super.makeNameForProperty(c, className, p, jsonName, undefined); } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - typeMapTypeFor (t: Type): Sourcelike { + private typeMapTypeFor(t: Type): Sourcelike { if (["class", "object", "enum"].includes(t.kind)) { - return ["r(\"", this.nameForNamedType(t), "\")"]; + return ['r("', this.nameForNamedType(t), '")']; } return matchType( t, - _anyType => "\"any\"", + _anyType => '"any"', _nullType => "null", _boolType => "true", _integerType => "0", _doubleType => "3.14", - _stringType => "\"\"", + _stringType => '""', arrayType => ["a(", this.typeMapTypeFor(arrayType.items), ")"], _classType => panic("We handled this above"), mapType => ["m(", this.typeMapTypeFor(mapType.values), ")"], @@ -196,12 +196,12 @@ export class JavaScriptRenderer extends ConvenienceRenderer { return "Date"; } - return "\"\""; - }, + return '""'; + } ); } - typeMapTypeForProperty (p: ClassProperty): Sourcelike { + private typeMapTypeForProperty(p: ClassProperty): Sourcelike { const typeMap = this.typeMapTypeFor(p.type); if (!p.isOptional) { return typeMap; @@ -210,13 +210,13 @@ export class JavaScriptRenderer extends ConvenienceRenderer { return ["u(undefined, ", typeMap, ")"]; } - emitBlock (source: Sourcelike, end: Sourcelike, emit: () => void) { + protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void) { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); } - emitTypeMap () { + private emitTypeMap() { const { any: anyAnnotation } = this.typeAnnotations; this.emitBlock(`const typeMap${anyAnnotation} = `, ";", () => { @@ -224,24 +224,24 @@ export class JavaScriptRenderer extends ConvenienceRenderer { const additionalProperties = t.getAdditionalProperties(); const additional = additionalProperties !== undefined ? this.typeMapTypeFor(additionalProperties) : "false"; - this.emitLine("\"", name, "\": o(["); + this.emitLine('"', name, '": o(['); this.indent(() => { this.forEachClassProperty(t, "none", (propName, jsonName, property) => { this.emitLine( - "{ json: \"", + '{ json: "', utf16StringEscape(jsonName), - "\", js: \"", + '", js: "', modifySource(utf16StringEscape, propName), - "\", typ: ", + '", typ: ', this.typeMapTypeForProperty(property), - " },", + " }," ); }); }); this.emitLine("], ", additional, "),"); }); this.forEachEnum("none", (e, name) => { - this.emitLine("\"", name, "\": ["); + this.emitLine('"', name, '": ['); this.indent(() => { this.forEachEnumCase(e, "none", (_caseName, jsonName) => { this.emitLine(`"${utf16StringEscape(jsonName)}",`); @@ -252,32 +252,32 @@ export class JavaScriptRenderer extends ConvenienceRenderer { }); } - protected deserializerFunctionName (name: Name): Sourcelike { + protected deserializerFunctionName(name: Name): Sourcelike { return ["to", name]; } - protected deserializerFunctionLine (_t: Type, name: Name): Sourcelike { + protected deserializerFunctionLine(_t: Type, name: Name): Sourcelike { return ["function ", this.deserializerFunctionName(name), "(json)"]; } - protected serializerFunctionName (name: Name): Sourcelike { + protected serializerFunctionName(name: Name): Sourcelike { const camelCaseName = modifySource(camelCase, name); return [camelCaseName, "ToJson"]; } - protected serializerFunctionLine (_t: Type, name: Name): Sourcelike { + protected serializerFunctionLine(_t: Type, name: Name): Sourcelike { return ["function ", this.serializerFunctionName(name), "(value)"]; } - protected get moduleLine (): string | undefined { + protected get moduleLine(): string | undefined { return undefined; } - protected get castFunctionLines (): [string, string] { + protected get castFunctionLines(): [string, string] { return ["function cast(val, typ)", "function uncast(val, typ)"]; } - protected get typeAnnotations (): JavaScriptTypeAnnotations { + protected get typeAnnotations(): JavaScriptTypeAnnotations { return { any: "", anyArray: "", @@ -285,11 +285,11 @@ export class JavaScriptRenderer extends ConvenienceRenderer { string: "", stringArray: "", boolean: "", - never: "", + never: "" }; } - protected emitConvertModuleBody (): void { + protected emitConvertModuleBody(): void { const converter = (t: Type, name: Name) => { const typeMap = this.typeMapTypeFor(t); this.emitBlock([this.deserializerFunctionLine(t, name), " "], "", () => { @@ -330,7 +330,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { } } - protected emitConvertModuleHelpers (): void { + protected emitConvertModuleHelpers(): void { if (this._jsOptions.runtimeTypecheck) { const { any: anyAnnotation, @@ -338,7 +338,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { anyMap: anyMapAnnotation, string: stringAnnotation, stringArray: stringArrayAnnotation, - never: neverAnnotation, + never: neverAnnotation } = this.typeAnnotations; this.ensureBlankLine(); this @@ -434,10 +434,10 @@ function transform(val${anyAnnotation}, typ${anyAnnotation}, getProps${anyAnnota Object.getOwnPropertyNames(val).forEach(key => { if (!Object.prototype.hasOwnProperty.call(props, key)) { result[key] = ${ - this._jsOptions.runtimeTypecheckIgnoreUnknownProperties - ? "val[key]" - : "transform(val[key], additional, getProps, key, ref)" -}; + this._jsOptions.runtimeTypecheckIgnoreUnknownProperties + ? "val[key]" + : "transform(val[key], additional, getProps, key, ref)" + }; } }); return result; @@ -502,14 +502,14 @@ function r(name${stringAnnotation}) { } } - protected emitConvertModule (): void { + protected emitConvertModule(): void { this.ensureBlankLine(); this.emitMultiline( - `// Converts JSON ${this._jsOptions.rawType === "json" ? "strings" : "types"} to/from your types`, + `// Converts JSON ${this._jsOptions.rawType === "json" ? "strings" : "types"} to/from your types` ); if (this._jsOptions.runtimeTypecheck) { this.emitMultiline( - `// and asserts the results${this._jsOptions.rawType === "json" ? " of JSON.parse" : ""} at runtime`, + `// and asserts the results${this._jsOptions.rawType === "json" ? " of JSON.parse" : ""} at runtime` ); } @@ -521,15 +521,15 @@ function r(name${stringAnnotation}) { } } - protected emitTypes (): void { + protected emitTypes(): void { return; } - protected emitUsageImportComment (): void { - this.emitLine("// const Convert = require(\"./file\");"); + protected emitUsageImportComment(): void { + this.emitLine('// const Convert = require("./file");'); } - protected emitUsageComments (): void { + protected emitUsageComments(): void { this.emitMultiline(`// To parse this data: //`); @@ -546,20 +546,20 @@ function r(name${stringAnnotation}) { } } - protected emitModuleExports (): void { + protected emitModuleExports(): void { this.ensureBlankLine(); this.emitBlock("module.exports = ", ";", () => { this.forEachTopLevel("none", (_, name) => { const serializer = this.serializerFunctionName(name); const deserializer = this.deserializerFunctionName(name); - this.emitLine("\"", serializer, "\": ", serializer, ","); - this.emitLine("\"", deserializer, "\": ", deserializer, ","); + this.emitLine('"', serializer, '": ', serializer, ","); + this.emitLine('"', deserializer, '": ', deserializer, ","); }); }); } - protected emitSourceStructure () { + protected emitSourceStructure() { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts index 7c8927f24..3b9348f0b 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts @@ -1,26 +1,13 @@ import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { getOptionValues, EnumOption } from "../RendererOptions"; import { type RenderContext } from "../Renderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; -import { - type ClassProperty, - type ClassType, - type ObjectType, - type Sourcelike, - type Type, -} from ".."; -import { - capitalize, - combineWords, - firstUpperWordStyle, - matchType, - panic, - splitIntoWords, -} from ".."; +import { type ClassProperty, type ClassType, type ObjectType, type Sourcelike, type Type } from ".."; +import { capitalize, combineWords, firstUpperWordStyle, matchType, panic, splitIntoWords } from ".."; import { allLowerWordStyle, utf16StringEscape } from "../support/Strings"; import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; import { legalizeName } from "./JavaScript"; @@ -37,29 +24,33 @@ export const javaScriptPropTypesOptions = { "Which module system to use", [ ["common-js", false], - ["es6", true], + ["es6", true] ], - "es6", - ), + "es6" + ) }; export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { - protected getOptions (): Array> { + protected getOptions(): Array> { return [javaScriptPropTypesOptions.acronymStyle, javaScriptPropTypesOptions.converters]; } - constructor (displayName = "JavaScript PropTypes", names: string[] = ["javascript-prop-types"], extension = "js") { + public constructor( + displayName = "JavaScript PropTypes", + names: string[] = ["javascript-prop-types"], + extension = "js" + ) { super(displayName, names, extension); } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): JavaScriptPropTypesRenderer { return new JavaScriptPropTypesRenderer( this, renderContext, - getOptionValues(javaScriptPropTypesOptions, untypedOptionValues), + getOptionValues(javaScriptPropTypesOptions, untypedOptionValues) ); } } @@ -67,15 +58,15 @@ export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { const identityNamingFunction = funPrefixNamer("properties", s => s); export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _jsOptions: OptionValues, + private readonly _jsOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected nameStyle (original: string, upper: boolean): string { + protected nameStyle(original: string, upper: boolean): string { const acronyms = acronymStyle(this._jsOptions.acronymStyle); const words = splitIntoWords(original); return combineWords( @@ -86,42 +77,42 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isES3IdentifierStart, + isES3IdentifierStart ); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return identityNamingFunction; } - protected makeUnionMemberNamer (): null { + protected makeUnionMemberNamer(): null { return null; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { return directlyReachableSingleNamedType(type); } - protected makeNameForProperty ( + protected makeNameForProperty( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - _assignedName: string | undefined, + _assignedName: string | undefined ): Name | undefined { // Ignore the assigned name return super.makeNameForProperty(c, className, p, jsonName, undefined); } - typeMapTypeFor (t: Type, required = true): Sourcelike { + private typeMapTypeFor(t: Type, required = true): Sourcelike { if (["class", "object", "enum"].includes(t.kind)) { return ["_", this.nameForNamedType(t)]; } @@ -140,13 +131,13 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { _enumType => panic("Should already be handled."), unionType => { const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false), + this.typeMapTypeFor(type, false) ); return ["PropTypes.oneOfType([", ...arrayIntercalate(", ", children), "])"]; }, _transformedStringType => { return "PropTypes.string"; - }, + } ); if (required) { @@ -156,11 +147,11 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { return match; } - typeMapTypeForProperty (p: ClassProperty): Sourcelike { + private typeMapTypeForProperty(p: ClassProperty): Sourcelike { return this.typeMapTypeFor(p.type); } - private importStatement (lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { + private importStatement(lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { if (this._jsOptions.moduleSystem) { return ["import ", lhs, " from ", moduleName, ";"]; } else { @@ -168,7 +159,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { } } - protected emitUsageComments (): void { + protected emitUsageComments(): void { // FIXME: Use the correct type name this.emitCommentLines( [ @@ -182,24 +173,24 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { "", "MyComponent.propTypes = {", " input: MyShape", - "};", + "};" ], - { lineStart: "// " }, + { lineStart: "// " } ); } - protected emitBlock (source: Sourcelike, end: Sourcelike, emit: () => void) { + protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void) { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); } - protected emitImports (): void { + protected emitImports(): void { this.ensureBlankLine(); - this.emitLine(this.importStatement("PropTypes", "\"prop-types\"")); + this.emitLine(this.importStatement("PropTypes", '"prop-types"')); } - private emitExport (name: Sourcelike, value: Sourcelike): void { + private emitExport(name: Sourcelike, value: Sourcelike): void { if (this._jsOptions.moduleSystem) { this.emitLine("export const ", name, " = ", value, ";"); } else { @@ -207,7 +198,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { } } - protected emitTypes (): void { + protected emitTypes(): void { this.ensureBlankLine(); this.forEachObject("none", (_type: ObjectType, name: Name) => { @@ -282,7 +273,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { }); } - private emitObject (name: Name, t: ObjectType) { + private emitObject(name: Name, t: ObjectType) { this.ensureBlankLine(); this.emitLine("_", name, " = PropTypes.shape({"); this.indent(() => { @@ -293,7 +284,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { this.emitLine("});"); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { diff --git a/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts b/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts index e818aaeb3..0e75bbfaa 100644 --- a/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts +++ b/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts @@ -1,6 +1,7 @@ +/* eslint-disable */ // Taken from https://github.com/Microsoft/TypeScript -function lookupInUnicodeMap (code: number, map: readonly number[]): boolean { +function lookupInUnicodeMap(code: number, map: readonly number[]): boolean { // Bail out quickly if it couldn't possibly be in the map. if (code < map[0]) { return false; @@ -45,24 +46,24 @@ const enum CharacterCodes { Z = 0x5a } -export function isES3IdentifierStart (ch: number): boolean { +export function isES3IdentifierStart(ch: number): boolean { return ( - ch >= CharacterCodes.A && ch <= CharacterCodes.Z || - ch >= CharacterCodes.a && ch <= CharacterCodes.z || + (ch >= CharacterCodes.A && ch <= CharacterCodes.Z) || + (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || ch === CharacterCodes.$ || ch === CharacterCodes._ || - ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierStart) + (ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierStart)) ); } -export function isES3IdentifierPart (ch: number): boolean { +export function isES3IdentifierPart(ch: number): boolean { return ( - ch >= CharacterCodes.A && ch <= CharacterCodes.Z || - ch >= CharacterCodes.a && ch <= CharacterCodes.z || - ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || + (ch >= CharacterCodes.A && ch <= CharacterCodes.Z) || + (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || + (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) || ch === CharacterCodes.$ || ch === CharacterCodes._ || - ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierPart) + (ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierPart)) ); } @@ -113,7 +114,7 @@ const unicodeES3IdentifierStart = [ 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65138, 65140, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, - 65482, 65487, 65490, 65495, 65498, 65500, + 65482, 65487, 65490, 65495, 65498, 65500 ]; const unicodeES3IdentifierPart = [ 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, @@ -152,5 +153,5 @@ const unicodeES3IdentifierPart = [ 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65056, 65059, 65075, 65076, 65101, 65103, 65136, 65138, 65140, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, - 65479, 65482, 65487, 65490, 65495, 65498, 65500, + 65479, 65482, 65487, 65490, 65495, 65498, 65500 ]; diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts index d88b58060..b2f46b466 100644 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ b/packages/quicktype-core/src/language/Kotlin.ts @@ -57,7 +57,7 @@ export const kotlinOptions = { }; export class KotlinTargetLanguage extends TargetLanguage { - constructor() { + public constructor() { super("Kotlin", ["kotlin"], "kt"); } @@ -65,11 +65,11 @@ export class KotlinTargetLanguage extends TargetLanguage { return [kotlinOptions.framework, kotlinOptions.acronymStyle, kotlinOptions.packageName]; } - get supportsOptionalClassProperties(): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } @@ -186,7 +186,7 @@ function stringEscape(s: string): string { } export class KotlinRenderer extends ConvenienceRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, protected readonly _kotlinOptions: OptionValues @@ -455,7 +455,7 @@ export class KotlinRenderer extends ConvenienceRenderer { } export class KotlinKlaxonRenderer extends KotlinRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, _kotlinOptions: OptionValues @@ -738,7 +738,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } export class KotlinJacksonRenderer extends KotlinRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, _kotlinOptions: OptionValues @@ -1012,7 +1012,7 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso * TODO: Union, Any, Top Level Array, Top Level Map */ export class KotlinXRenderer extends KotlinRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, _kotlinOptions: OptionValues diff --git a/packages/quicktype-core/src/language/Objective-C.ts b/packages/quicktype-core/src/language/Objective-C.ts index 00235121c..e97381a00 100644 --- a/packages/quicktype-core/src/language/Objective-C.ts +++ b/packages/quicktype-core/src/language/Objective-C.ts @@ -4,9 +4,9 @@ import { TargetLanguage } from "../TargetLanguage"; import { type ClassProperty } from "../Type"; import { Type, ClassType, EnumType, ArrayType, MapType, UnionType } from "../Type"; import { matchType, nullableFromUnion, isAnyOrNull } from "../TypeUtils"; -import { type Name} from "../Naming"; +import { type Name } from "../Naming"; import { Namer, funPrefixNamer } from "../Naming"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { modifySource } from "../Source"; import { splitIntoWords, @@ -19,7 +19,7 @@ import { stringEscape, addPrefixIfNecessary, repeatString, - fastIsUpperCase, + fastIsUpperCase } from "../support/Strings"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; @@ -32,7 +32,8 @@ import unicode from "unicode-properties"; export type MemoryAttribute = "assign" | "strong" | "copy"; export interface OutputFeatures { - implementation: boolean; interface: boolean; + implementation: boolean; + interface: boolean; } const DEBUG = false; @@ -42,38 +43,38 @@ export const objcOptions = { features: new EnumOption("features", "Interface and implementation", [ ["all", { interface: true, implementation: true }], ["interface", { interface: true, implementation: false }], - ["implementation", { interface: false, implementation: true }], + ["implementation", { interface: false, implementation: true }] ]), justTypes: new BooleanOption("just-types", "Plain types only", false), marshallingFunctions: new BooleanOption("functions", "C-style functions", false), classPrefix: new StringOption("class-prefix", "Class prefix", "PREFIX", DEFAULT_CLASS_PREFIX), - extraComments: new BooleanOption("extra-comments", "Extra comments", false), + extraComments: new BooleanOption("extra-comments", "Extra comments", false) }; export class ObjectiveCTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Objective-C", ["objc", "objective-c", "objectivec"], "m"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ objcOptions.justTypes, objcOptions.classPrefix, objcOptions.features, objcOptions.extraComments, - objcOptions.marshallingFunctions, + objcOptions.marshallingFunctions ]; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): ObjectiveCRenderer { return new ObjectiveCRenderer(this, renderContext, getOptionValues(objcOptions, untypedOptionValues)); } } -function typeNameStyle (prefix: string, original: string): string { +function typeNameStyle(prefix: string, original: string): string { const words = splitIntoWords(original); const result = combineWords( words, @@ -83,12 +84,12 @@ function typeNameStyle (prefix: string, original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter, + isStartCharacter ); return addPrefixIfNecessary(prefix, result); } -function propertyNameStyle (original: string, isBool = false): string { +function propertyNameStyle(original: string, isBool = false): string { // Objective-C developers are uncomfortable with property "id" // so we use an alternate name in this special case. if (original === "id") { @@ -119,7 +120,7 @@ function propertyNameStyle (original: string, isBool = false): string { allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter, + isStartCharacter ); } @@ -171,7 +172,7 @@ const keywords = [ "unsigned", "void", "volatile", - "while", + "while" ]; const forbiddenPropertyNames = [ @@ -183,7 +184,7 @@ const forbiddenPropertyNames = [ "mutableCopy", "superclass", "debugDescription", - "new", + "new" ]; const booleanPrefixes = [ @@ -203,14 +204,14 @@ const booleanPrefixes = [ "requires", "require", "needs", - "need", + "need" ]; -function isStartCharacter (utf16Unit: number): boolean { +function isStartCharacter(utf16Unit: number): boolean { return unicode.isAlphabetic(utf16Unit) || utf16Unit === 0x5f; // underscore } -function isPartCharacter (utf16Unit: number): boolean { +function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } @@ -220,7 +221,7 @@ const legalizeName = utf16LegalizeCharacters(isPartCharacter); const staticEnumValuesIdentifier = "values"; const forbiddenForEnumCases = ["new", staticEnumValuesIdentifier]; -function splitExtension (filename: string): [string, string] { +function splitExtension(filename: string): [string, string] { const i = filename.lastIndexOf("."); const extension = i !== -1 ? filename.split(".").pop() : "m"; filename = i !== -1 ? filename.slice(0, i) : filename; @@ -232,10 +233,10 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { private readonly _classPrefix: string; - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); @@ -248,7 +249,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } } - private inferClassPrefix (name: string): string { + private inferClassPrefix(name: string): string { const l = name.length; let firstNonUpper = 0; while (firstNonUpper < l && fastIsUpperCase(name.charCodeAt(firstNonUpper))) { @@ -259,88 +260,88 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return name.slice(0, firstNonUpper - 1); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: forbiddenPropertyNames, includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: forbiddenForEnumCases, includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("types", rawName => typeNameStyle(this._classPrefix, rawName)); } - protected namerForObjectProperty (_: ClassType, p: ClassProperty): Namer { + protected namerForObjectProperty(_: ClassType, p: ClassProperty): Namer { // TODO why is underscore being removed? return new Namer("properties", s => propertyNameStyle(s, p.type.kind === "bool"), [ "_", "the", "one", "some", - "another", + "another" ]); } - protected makeUnionMemberNamer (): null { + protected makeUnionMemberNamer(): null { return null; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return new Namer("enum-cases", propertyNameStyle, []); } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { return type; } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: "/// " }); } - protected emitBlock (line: Sourcelike, f: () => void): void { + protected emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected emitMethod (declaration: Sourcelike, f: () => void) { + protected emitMethod(declaration: Sourcelike, f: () => void) { this.emitLine(declaration); this.emitLine("{"); this.indent(f); this.emitLine("}"); } - protected emitExtraComments (...comments: Sourcelike[]) { + protected emitExtraComments(...comments: Sourcelike[]) { if (!this._options.extraComments) return; for (const comment of comments) { this.emitLine("// ", comment); } } - protected startFile (basename: Sourcelike, extension: string): void { + protected startFile(basename: Sourcelike, extension: string): void { assert(this._currentFilename === undefined, "Previous file wasn't finished"); // FIXME: The filenames should actually be Sourcelikes, too this._currentFilename = `${this.sourcelikeToString(basename)}.${extension}`; } - protected finishFile (): void { + protected finishFile(): void { super.finishFile(defined(this._currentFilename)); this._currentFilename = undefined; } - protected memoryAttribute (t: Type, isNullable: boolean): MemoryAttribute { + protected memoryAttribute(t: Type, isNullable: boolean): MemoryAttribute { return matchType( t, _anyType => "copy", _nullType => "copy", - _boolType => isNullable ? "strong" : "assign", - _integerType => isNullable ? "strong" : "assign", - _doubleType => isNullable ? "strong" : "assign", + _boolType => (isNullable ? "strong" : "assign"), + _integerType => (isNullable ? "strong" : "assign"), + _doubleType => (isNullable ? "strong" : "assign"), _stringType => "copy", _arrayType => "copy", _classType => "strong", @@ -349,19 +350,19 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.memoryAttribute(nullable, true) : "copy"; - }, + } ); } - protected objcType (t: Type, nullableOrBoxed = false): [Sourcelike, string] { + protected objcType(t: Type, nullableOrBoxed = false): [Sourcelike, string] { return matchType<[Sourcelike, string]>( t, _anyType => ["id", ""], // For now, we're treating nulls just like any _nullType => ["id", ""], - _boolType => nullableOrBoxed ? ["NSNumber", " *"] : ["BOOL", ""], - _integerType => nullableOrBoxed ? ["NSNumber", " *"] : ["NSInteger", ""], - _doubleType => nullableOrBoxed ? ["NSNumber", " *"] : ["double", ""], + _boolType => (nullableOrBoxed ? ["NSNumber", " *"] : ["BOOL", ""]), + _integerType => (nullableOrBoxed ? ["NSNumber", " *"] : ["NSInteger", ""]), + _doubleType => (nullableOrBoxed ? ["NSNumber", " *"] : ["double", ""]), _stringType => ["NSString", " *"], arrayType => { const itemType = arrayType.items; @@ -379,11 +380,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.objcType(nullable, true) : ["id", ""]; - }, + } ); } - private jsonType (t: Type): [Sourcelike, string] { + private jsonType(t: Type): [Sourcelike, string] { return matchType<[Sourcelike, string]>( t, _anyType => ["id", ""], @@ -400,11 +401,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.jsonType(nullable) : ["id", ""]; - }, + } ); } - protected fromDynamicExpression (t: Type, ...dynamic: Sourcelike[]): Sourcelike { + protected fromDynamicExpression(t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, _anyType => dynamic, @@ -420,11 +421,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { unionType => { const nullable = nullableFromUnion(unionType); return nullable !== null ? this.fromDynamicExpression(nullable, dynamic) : dynamic; - }, + } ); } - protected toDynamicExpression (t: Type, typed: Sourcelike): Sourcelike { + protected toDynamicExpression(t: Type, typed: Sourcelike): Sourcelike { return matchType( t, _anyType => ["NSNullify(", typed, ")"], @@ -464,11 +465,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { // TODO support unions return typed; } - }, + } ); } - protected implicitlyConvertsFromJSON (t: Type): boolean { + protected implicitlyConvertsFromJSON(t: Type): boolean { if (t instanceof ClassType) { return false; } else if (t instanceof EnumType) { @@ -492,11 +493,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } } - protected implicitlyConvertsToJSON (t: Type): boolean { + protected implicitlyConvertsToJSON(t: Type): boolean { return this.implicitlyConvertsFromJSON(t) && "bool" !== t.kind; } - protected emitPropertyAssignment (propertyName: Name, jsonName: string, propertyType: Type) { + protected emitPropertyAssignment(propertyName: Name, jsonName: string, propertyType: Type) { const name = ["_", propertyName]; matchType( propertyType, @@ -516,7 +517,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { name, ", ", ["λ(id x, ", this.fromDynamicExpression(itemType, "x"), ")"], - ");", + ");" ); }, enumType => this.emitLine(name, " = ", this.fromDynamicExpression(enumType, ["(id)", name]), ";"), @@ -528,43 +529,43 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { // TODO This is a union, but for now we just leave it dynamic this.emitLine(name, " = ", this.fromDynamicExpression(unionType, name), ";"); } - }, + } ); } - protected emitPrivateClassInterface (_: ClassType, name: Name): void { + protected emitPrivateClassInterface(_: ClassType, name: Name): void { this.emitLine("@interface ", name, " (JSONConversion)"); this.emitLine("+ (instancetype)fromJSONDictionary:(NSDictionary *)dict;"); this.emitLine("- (NSDictionary *)JSONDictionary;"); this.emitLine("@end"); } - protected pointerAwareTypeName (t: Type | [Sourcelike, string]): Sourcelike { + protected pointerAwareTypeName(t: Type | [Sourcelike, string]): Sourcelike { const name = t instanceof Type ? this.objcType(t) : t; const isPointer = name[1] !== ""; return isPointer ? name : [name, " "]; } - private emitNonClassTopLevelTypedef (t: Type, name: Name): void { + private emitNonClassTopLevelTypedef(t: Type, name: Name): void { let nonPointerTypeName = this.objcType(t)[0]; this.emitLine("typedef ", nonPointerTypeName, " ", name, ";"); } - private topLevelFromDataPrototype (name: Name): Sourcelike { + private topLevelFromDataPrototype(name: Name): Sourcelike { return [name, " *_Nullable ", name, "FromData(NSData *data, NSError **error)"]; } - private topLevelFromJSONPrototype (name: Name): Sourcelike { + private topLevelFromJSONPrototype(name: Name): Sourcelike { return [name, " *_Nullable ", name, "FromJSON(NSString *json, NSStringEncoding encoding, NSError **error)"]; } - private topLevelToDataPrototype (name: Name, pad = false): Sourcelike { + private topLevelToDataPrototype(name: Name, pad = false): Sourcelike { const parameter = this.variableNameForTopLevel(name); const padding = pad ? repeatString(" ", this.sourcelikeToString(name).length - "NSData".length) : ""; return ["NSData", padding, " *_Nullable ", name, "ToData(", name, " *", parameter, ", NSError **error)"]; } - private topLevelToJSONPrototype (name: Name, pad = false): Sourcelike { + private topLevelToJSONPrototype(name: Name, pad = false): Sourcelike { const parameter = this.variableNameForTopLevel(name); const padding = pad ? repeatString(" ", this.sourcelikeToString(name).length - "NSString".length) : ""; return [ @@ -576,31 +577,31 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { name, " *", parameter, - ", NSStringEncoding encoding, NSError **error)", + ", NSStringEncoding encoding, NSError **error)" ]; } - private emitTopLevelFunctionDeclarations (_: Type, name: Name): void { + private emitTopLevelFunctionDeclarations(_: Type, name: Name): void { this.emitLine(this.topLevelFromDataPrototype(name), ";"); this.emitLine(this.topLevelFromJSONPrototype(name), ";"); this.emitLine(this.topLevelToDataPrototype(name, true), ";"); this.emitLine(this.topLevelToJSONPrototype(name, true), ";"); } - private emitTryCatchAsError (inTry: () => void, inCatch: () => void) { + private emitTryCatchAsError(inTry: () => void, inCatch: () => void) { this.emitLine("@try {"); this.indent(inTry); this.emitLine("} @catch (NSException *exception) {"); this.indent(() => { this.emitLine( - "*error = [NSError errorWithDomain:@\"JSONSerialization\" code:-1 userInfo:@{ @\"exception\": exception }];", + '*error = [NSError errorWithDomain:@"JSONSerialization" code:-1 userInfo:@{ @"exception": exception }];' ); inCatch(); }); this.emitLine("}"); } - private emitTopLevelFunctions (t: Type, name: Name): void { + private emitTopLevelFunctions(t: Type, name: Name): void { const parameter = this.variableNameForTopLevel(name); this.ensureBlankLine(); @@ -608,11 +609,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitTryCatchAsError( () => { this.emitLine( - "id json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:error];", + "id json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:error];" ); this.emitLine("return *error ? nil : ", this.fromDynamicExpression(t, "json"), ";"); }, - () => this.emitLine("return nil;"), + () => this.emitLine("return nil;") ); }); @@ -627,11 +628,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { () => { this.emitLine("id json = ", this.toDynamicExpression(t, parameter), ";"); this.emitLine( - "NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:error];", + "NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:error];" ); this.emitLine("return *error ? nil : data;"); }, - () => this.emitLine("return nil;"), + () => this.emitLine("return nil;") ); }); @@ -642,7 +643,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { }); } - private emitClassInterface (t: ClassType, className: Name): void { + private emitClassInterface(t: ClassType, className: Name): void { const isTopLevel = mapContains(this.topLevels, t); this.emitDescription(this.descriptionForType(t)); @@ -660,7 +661,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { attributes.push(this.memoryAttribute(property.type, property.type.isNullable)); return [ ["@property ", ["(", attributes.join(", "), ")"], " "], - [this.pointerAwareTypeName(property.type), name, ";"], + [this.pointerAwareTypeName(property.type), name, ";"] ]; }); @@ -668,11 +669,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (t.getProperties().size > 0) this.ensureBlankLine(); this.emitLine( - "+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;", + "+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;" ); this.emitLine("+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error;"); this.emitLine( - "- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;", + "- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;" ); this.emitLine("- (NSData *_Nullable)toData:(NSError *_Nullable *)error;"); } @@ -680,7 +681,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - protected hasIrregularProperties (t: ClassType) { + protected hasIrregularProperties(t: ClassType) { let irregular = false; this.forEachClassProperty(t, "none", (name, jsonName) => { irregular = irregular || stringEscape(jsonName) !== this.sourcelikeToString(name); @@ -688,7 +689,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return irregular; } - protected hasUnsafeProperties (t: ClassType) { + protected hasUnsafeProperties(t: ClassType) { let unsafe = false; this.forEachClassProperty(t, "none", (_, __, property) => { unsafe = unsafe || !this.implicitlyConvertsToJSON(property.type); @@ -697,7 +698,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } // TODO Implement NSCopying - private emitClassImplementation (t: ClassType, className: Name): void { + private emitClassImplementation(t: ClassType, className: Name): void { const isTopLevel = mapContains(this.topLevels, t); const hasIrregularProperties = this.hasIrregularProperties(t); @@ -710,7 +711,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("return properties = properties ? properties : @{"); this.indent(() => { this.forEachClassProperty(t, "none", (name, jsonName) => - this.emitLine(`@"${stringEscape(jsonName)}": @"`, name, "\","), + this.emitLine(`@"${stringEscape(jsonName)}": @"`, name, '",') ); }); this.emitLine("};"); @@ -722,14 +723,14 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error", () => { this.emitLine("return ", className, "FromData(data, error);"); - }, + } ); this.ensureBlankLine(); this.emitMethod( "+ (_Nullable instancetype)fromJSON:(NSString *)json encoding:(NSStringEncoding)encoding error:(NSError *_Nullable *)error", () => { this.emitLine("return ", className, "FromJSON(json, encoding, error);"); - }, + } ); this.ensureBlankLine(); } @@ -777,7 +778,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine( "id dict = [[self dictionaryWithValuesForKeys:", className, - ".properties.allValues] mutableCopy];", + ".properties.allValues] mutableCopy];" ); this.ensureBlankLine(); @@ -801,7 +802,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (!this.implicitlyConvertsToJSON(property.type)) { const key = stringEscape(jsonKey); const name = ["_", propertyName]; - this.emitLine("@\"", key, "\": ", this.toDynamicExpression(property.type, name), ","); + this.emitLine('@"', key, '": ', this.toDynamicExpression(property.type, name), ","); } }); }); @@ -822,7 +823,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error", () => { this.emitLine("return ", className, "ToJSON(self, encoding, error);"); - }, + } ); } } @@ -830,13 +831,13 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - protected emitMark (label: string) { + protected emitMark(label: string) { this.ensureBlankLine(); this.emitLine(`#pragma mark - ${label}`); this.ensureBlankLine(); } - protected variableNameForTopLevel (name: Name): Sourcelike { + protected variableNameForTopLevel(name: Name): Sourcelike { const camelCaseName = modifySource(serialized => { // 1. remove class prefix serialized = serialized.slice(this._classPrefix.length); @@ -846,7 +847,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return camelCaseName; } - private emitPseudoEnumInterface (enumType: EnumType, enumName: Name) { + private emitPseudoEnumInterface(enumType: EnumType, enumName: Name) { this.emitDescription(this.descriptionForType(enumType)); this.emitLine("@interface ", enumName, " : NSObject"); @@ -858,7 +859,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - private emitPseudoEnumImplementation (enumType: EnumType, enumName: Name) { + private emitPseudoEnumImplementation(enumType: EnumType, enumName: Name) { this.emitLine("@implementation ", enumName); const instances = [enumName, ".", staticEnumValuesIdentifier]; @@ -871,11 +872,11 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { staticEnumValuesIdentifier, " ? ", staticEnumValuesIdentifier, - " : @{", + " : @{" ); this.indent(() => { this.forEachEnumCase(enumType, "none", (_, jsonValue) => { - const value = ["@\"", stringEscape(jsonValue), "\""]; + const value = ['@"', stringEscape(jsonValue), '"']; this.emitLine(value, ": [[", enumName, " alloc] initWithValue:", value, "],"); }); }); @@ -891,15 +892,15 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { name, " { return ", instances, - "[@\"", + '[@"', stringEscape(jsonValue), - "\"]; }", + '"]; }' ); }); this.ensureBlankLine(); this.emitMethod("+ (instancetype _Nullable)withValue:(NSString *)value", () => - this.emitLine("return ", instances, "[value];"), + this.emitLine("return ", instances, "[value];") ); this.ensureBlankLine(); @@ -913,7 +914,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - protected emitSourceStructure (proposedFilename: string): void { + protected emitSourceStructure(proposedFilename: string): void { const fileMode = proposedFilename !== "stdout"; if (!fileMode) { // We don't have a filename, so we use a top-level name @@ -942,7 +943,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { " *", this.variableNameForTopLevel(topLevelName), " = ", - fromJsonExpression, + fromJsonExpression ); }); } @@ -956,7 +957,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "none", (_: ClassType, className: Name) => this.emitLine("@class ", className, ";"), (_, enumName) => this.emitLine("@class ", enumName, ";"), - () => null, + () => null ); this.ensureBlankLine(); @@ -973,7 +974,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.forEachTopLevel( "leading-and-interposing", (t, n) => this.emitNonClassTopLevelTypedef(t, n), - t => !(t instanceof ClassType), + t => !(t instanceof ClassType) ); const hasTopLevelNonClassTypes = iterableSome(this.topLevels, ([_, t]) => !(t instanceof ClassType)); @@ -985,7 +986,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { (t, n) => this.emitTopLevelFunctionDeclarations(t, n), // Objective-C developers get freaked out by C functions, so we don't // declare them for top-level object types (we always need them for non-object types) - t => this._options.marshallingFunctions || !(t instanceof ClassType), + t => this._options.marshallingFunctions || !(t instanceof ClassType) ); } @@ -994,7 +995,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassInterface(c, className), () => null, - () => null, + () => null ); this.ensureBlankLine(); @@ -1015,7 +1016,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitExtraComments("nil → NSNull conversion for JSON dictionaries"); this.emitBlock("static id NSNullify(id _Nullable x)", () => - this.emitLine("return (x == nil || x == NSNull.null) ? NSNull.null : x;"), + this.emitLine("return (x == nil || x == NSNull.null) ? NSNull.null : x;") ); this.ensureBlankLine(); this.emitLine("NS_ASSUME_NONNULL_BEGIN"); @@ -1031,7 +1032,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, className: Name) => this.emitPrivateClassInterface(c, className), () => null, - () => null, + () => null ); if (this.haveEnums) { @@ -1039,7 +1040,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitExtraComments( "These enum-like reference types are needed so that enum", - "values can be contained by NSArray and NSDictionary.", + "values can be contained by NSArray and NSDictionary." ); this.ensureBlankLine(); } @@ -1059,7 +1060,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassImplementation(c, className), () => null, - () => null, + () => null ); if (!this._options.justTypes) { @@ -1071,20 +1072,20 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } } - private get needsMap (): boolean { + private get needsMap(): boolean { // TODO this isn't complete (needs union support, for example) - function needsMap (t: Type): boolean { + function needsMap(t: Type): boolean { return ( t instanceof MapType || t instanceof ArrayType || - t instanceof ClassType && mapSome(t.getProperties(), p => needsMap(p.type)) + (t instanceof ClassType && mapSome(t.getProperties(), p => needsMap(p.type))) ); } return iterableSome(this.typeGraph.allTypesUnordered(), needsMap); } - protected emitMapFunction () { + protected emitMapFunction() { if (this.needsMap) { this.emitMultiline(`static id map(id collection, id (^f)(id value)) { id result = nil; diff --git a/packages/quicktype-core/src/language/Php.ts b/packages/quicktype-core/src/language/Php.ts index 87c9e2b1c..8a7eaa40b 100644 --- a/packages/quicktype-core/src/language/Php.ts +++ b/packages/quicktype-core/src/language/Php.ts @@ -21,7 +21,7 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters, + utf16LegalizeCharacters } from "../support/Strings"; import { defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; @@ -35,28 +35,28 @@ export const phpOptions = { fastGet: new BooleanOption("fast-get", "getter without validation", false), withSet: new BooleanOption("with-set", "Create Setter", false), withClosing: new BooleanOption("with-closing", "PHP Closing Tag", false), - acronymStyle: acronymOption(AcronymStyleOptions.Pascal), + acronymStyle: acronymOption(AcronymStyleOptions.Pascal) }; export class PhpTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("PHP", ["php"], "php"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return _.values(phpOptions); } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): PhpRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): PhpRenderer { const options = getOptionValues(phpOptions, untypedOptionValues); return new PhpRenderer(this, renderContext, options); } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date", "date"); // TODO is not implemented yet mapping.set("time", "time"); // TODO is not implemented yet @@ -68,22 +68,22 @@ export class PhpTargetLanguage extends TargetLanguage { export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); -function isStartCharacter (codePoint: number): boolean { +function isStartCharacter(codePoint: number): boolean { if (codePoint === 0x5f) return true; // underscore return isAscii(codePoint) && isLetter(codePoint); } -function isPartCharacter (codePoint: number): boolean { - return isStartCharacter(codePoint) || isAscii(codePoint) && isDigit(codePoint); +function isPartCharacter(codePoint: number): boolean { + return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); -export function phpNameStyle ( +export function phpNameStyle( startWithUpper: boolean, upperUnderscore: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle, + acronymsStyle: (s: string) => string = allUpperWordStyle ): string { const words = splitIntoWords(original); return combineWords( @@ -94,7 +94,7 @@ export function phpNameStyle ( upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, upperUnderscore ? "_" : "", - isStartCharacter, + isStartCharacter ); } @@ -116,78 +116,78 @@ export class PhpRenderer extends ConvenienceRenderer { protected readonly _converterKeywords: string[] = []; - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues, + protected readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return this.getNameStyling("typeNamingFunction"); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return this.getNameStyling("propertyNamingFunction"); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return this.getNameStyling("enumCaseNamingFunction"); } - protected unionNeedsName (u: UnionType): boolean { + protected unionNeedsName(u: UnionType): boolean { return nullableFromUnion(u) === null; } - protected namedTypeToNameForTopLevel (type: Type): Type | undefined { + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { return directlyReachableSingleNamedType(type); } - protected makeNamesForPropertyGetterAndSetter ( + protected makeNamesForPropertyGetterAndSetter( _c: ClassType, _className: Name, _p: ClassProperty, _jsonName: string, - name: Name, + name: Name ): FunctionNames { const getterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `get_${lookup(name)}`, + lookup => `get_${lookup(name)}` ); const setterName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `set_${lookup(name)}`, + lookup => `set_${lookup(name)}` ); const validateName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `validate_${lookup(name)}`, + lookup => `validate_${lookup(name)}` ); const fromName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `from_${lookup(name)}`, + lookup => `from_${lookup(name)}` ); const toName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `to_${lookup(name)}`, + lookup => `to_${lookup(name)}` ); const sampleName = new DependencyName( this.getNameStyling("propertyNamingFunction"), name.order, - lookup => `sample_${lookup(name)}`, + lookup => `sample_${lookup(name)}` ); return { getter: getterName, @@ -195,16 +195,16 @@ export class PhpRenderer extends ConvenienceRenderer { validate: validateName, from: fromName, to: toName, - sample: sampleName, + sample: sampleName }; } - protected makePropertyDependencyNames ( + protected makePropertyDependencyNames( c: ClassType, className: Name, p: ClassProperty, jsonName: string, - name: Name, + name: Name ): Name[] { const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); @@ -214,26 +214,26 @@ export class PhpRenderer extends ConvenienceRenderer { getterAndSetterNames.validate, getterAndSetterNames.to, getterAndSetterNames.from, - getterAndSetterNames.sample, + getterAndSetterNames.sample ]; } - private getNameStyling (convention: string): Namer { - const styling: { [key: string]: Namer, } = { + private getNameStyling(convention: string): Namer { + const styling: { [key: string]: Namer } = { typeNamingFunction: funPrefixNamer("types", n => - phpNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)), + phpNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)) ), propertyNamingFunction: funPrefixNamer("properties", n => - phpNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)), + phpNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)) ), enumCaseNamingFunction: funPrefixNamer("enum-cases", n => - phpNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)), - ), + phpNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)) + ) }; return styling[convention]; } - protected startFile (_basename: Sourcelike): void { + protected startFile(_basename: Sourcelike): void { this.ensureBlankLine(); if (!this._haveEmittedLeadingComments && this.leadingComments !== undefined) { this.emitComments(this.leadingComments); @@ -242,28 +242,28 @@ export class PhpRenderer extends ConvenienceRenderer { } } - protected finishFile (): void { + protected finishFile(): void { // empty } - protected emitFileHeader (fileName: Sourcelike, _imports: string[]): void { + protected emitFileHeader(fileName: Sourcelike, _imports: string[]): void { this.startFile(fileName); this.emitLine("// This is a autogenerated file:", fileName); this.ensureBlankLine(); } - public emitDescriptionBlock (lines: Sourcelike[]): void { + public emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); } - public emitBlock (line: Sourcelike, f: () => void): void { + public emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - protected phpType (_reference: boolean, t: Type, isOptional = false, prefix = "?", suffix = ""): Sourcelike { - function optionalize (s: Sourcelike) { + protected phpType(_reference: boolean, t: Type, isOptional = false, prefix = "?", suffix = ""): Sourcelike { + function optionalize(s: Sourcelike) { return [isOptional ? prefix : "", s, isOptional ? suffix : ""]; } @@ -286,11 +286,11 @@ export class PhpRenderer extends ConvenienceRenderer { }, transformedStringType => { if (transformedStringType.kind === "time") { - throw Error("transformedStringType.kind === \"time\""); + throw Error('transformedStringType.kind === "time"'); } if (transformedStringType.kind === "date") { - throw Error("transformedStringType.kind === \"date\""); + throw Error('transformedStringType.kind === "date"'); } if (transformedStringType.kind === "date-time") { @@ -298,15 +298,15 @@ export class PhpRenderer extends ConvenienceRenderer { } if (transformedStringType.kind === "uuid") { - throw Error("transformedStringType.kind === \"uuid\""); + throw Error('transformedStringType.kind === "uuid"'); } return "string"; - }, + } ); } - protected phpDocConvertType (className: Name, t: Type): Sourcelike { + protected phpDocConvertType(className: Name, t: Type): Sourcelike { return matchType( t, _anyType => "any", @@ -332,12 +332,12 @@ export class PhpRenderer extends ConvenienceRenderer { return "DateTime"; } - throw Error("transformedStringType.kind === \"unknown\""); - }, + throw Error('transformedStringType.kind === "unknown"'); + } ); } - protected phpConvertType (className: Name, t: Type): Sourcelike { + protected phpConvertType(className: Name, t: Type): Sourcelike { return matchType( t, _anyType => "any", @@ -363,12 +363,12 @@ export class PhpRenderer extends ConvenienceRenderer { return "string"; } - throw Error("transformedStringType.kind === \"unknown\""); - }, + throw Error('transformedStringType.kind === "unknown"'); + } ); } - protected phpToObjConvert (className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { + protected phpToObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), @@ -416,21 +416,21 @@ export class PhpRenderer extends ConvenienceRenderer { return; } - throw Error("transformedStringType.kind === \"unknown\""); - }, + throw Error('transformedStringType.kind === "unknown"'); + } ); } - private transformDateTime (className: Name, attrName: Sourcelike, scopeAttrName: Sourcelike[]) { + private transformDateTime(className: Name, attrName: Sourcelike, scopeAttrName: Sourcelike[]) { this.emitBlock(["if (!is_a(", scopeAttrName, ", 'DateTime'))"], () => - this.emitLine("throw new Exception('Attribute Error:", className, "::", attrName, "');"), + this.emitLine("throw new Exception('Attribute Error:", className, "::", attrName, "');") ); // if (lhs !== undefined) { // this.emitLine(lhs, "$tmp;"); // } } - protected phpFromObjConvert (className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { + protected phpFromObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), @@ -481,18 +481,18 @@ export class PhpRenderer extends ConvenienceRenderer { return; } - throw Error("transformedStringType.kind === \"unknown\""); - }, + throw Error('transformedStringType.kind === "unknown"'); + } ); } - protected phpSampleConvert ( + protected phpSampleConvert( className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[], idx: number, - suffix: Sourcelike, + suffix: Sourcelike ) { matchType( t, @@ -510,7 +510,7 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/", + "*/" ), _nullType => this.emitLine(...lhs, "null", suffix, " /*", "" + idx, ":", args, "*/"), _boolType => this.emitLine(...lhs, "true", suffix, " /*", "" + idx, ":", args, "*/"), @@ -530,7 +530,7 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/", + "*/" ), arrayType => { this.emitLine(...lhs, " array("); @@ -549,7 +549,7 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/", + "*/" ), mapType => { this.emitBlock(["function sample(): stdClass"], () => { @@ -571,27 +571,27 @@ export class PhpRenderer extends ConvenienceRenderer { }, transformedStringType => { if (transformedStringType.kind === "date-time") { - const x = _.pad("" + (1 + idx % 31), 2, "0"); + const x = _.pad("" + (1 + (idx % 31)), 2, "0"); this.emitLine( ...lhs, "DateTime::createFromFormat(DateTimeInterface::ISO8601, '", `2020-12-${x}T12:${x}:${x}+00:00`, "')", - suffix, + suffix ); // this.emitLine("return sample();"); return; } - throw Error("transformedStringType.kind === \"unknown\""); - }, + throw Error('transformedStringType.kind === "unknown"'); + } ); } - private phpValidate (className: Name, t: Type, attrName: Sourcelike, scopeAttrName: string) { + private phpValidate(className: Name, t: Type, attrName: Sourcelike, scopeAttrName: string) { const is = (isfn: string, myT: Name = className) => { this.emitBlock(["if (!", isfn, "(", scopeAttrName, "))"], () => - this.emitLine("throw new Exception(\"Attribute Error:", myT, "::", attrName, "\");"), + this.emitLine('throw new Exception("Attribute Error:', myT, "::", attrName, '");') ); }; @@ -642,11 +642,11 @@ export class PhpRenderer extends ConvenienceRenderer { } throw Error(`transformedStringType.kind === ${transformedStringType.kind}`); - }, + } ); } - protected emitFromMethod (names: FunctionNames, p: ClassProperty, className: Name, _name: Name, desc?: string[]) { + protected emitFromMethod(names: FunctionNames, p: ClassProperty, className: Name, _name: Name, desc?: string[]) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); @@ -665,16 +665,16 @@ export class PhpRenderer extends ConvenienceRenderer { "(", this.phpConvertType(className, p.type), " $value): ", - this.phpType(false, p.type), + this.phpType(false, p.type) ], () => { this.phpFromObjConvert(className, p.type, ["return "], ["$value"]); // this.emitLine("return $ret;"); - }, + } ); } - protected emitToMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitToMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); @@ -692,7 +692,7 @@ export class PhpRenderer extends ConvenienceRenderer { }); } - protected emitValidateMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitValidateMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); @@ -708,11 +708,11 @@ export class PhpRenderer extends ConvenienceRenderer { () => { this.phpValidate(className, p.type, name, "$value"); this.emitLine("return true;"); - }, + } ); } - protected emitGetMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitGetMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { if (this._options.withGet) { this.emitLine("/**"); if (desc !== undefined) { @@ -739,7 +739,7 @@ export class PhpRenderer extends ConvenienceRenderer { className, "::", name, - "');", + "');" ); } else { this.emitLine("return $this->", name, ";"); @@ -748,7 +748,7 @@ export class PhpRenderer extends ConvenienceRenderer { } } - protected emitSetMethod (names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitSetMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { if (this._options.withSet) { this.emitLine("/**"); if (desc !== undefined) { @@ -767,13 +767,13 @@ export class PhpRenderer extends ConvenienceRenderer { } } - protected emitSampleMethod ( + protected emitSampleMethod( names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc: string[] | undefined, - idx: number, + idx: number ) { if (this._options.withGet) { this.emitLine("/**"); @@ -791,7 +791,7 @@ export class PhpRenderer extends ConvenienceRenderer { } } - protected emitClassDefinition (c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name): void { this.emitFileHeader(className, []); this.emitBlock(["class ", className], () => { @@ -804,7 +804,7 @@ export class PhpRenderer extends ConvenienceRenderer { "; // json:", jsonName, " ", - p.type.isNullable ? "Optional" : "Required", + p.type.isNullable ? "Optional" : "Required" ); }); @@ -856,7 +856,7 @@ export class PhpRenderer extends ConvenienceRenderer { lines.forEach((line, jdx) => { this.emitLine(...line, lines.length === jdx + 1 ? ";" : ""); }); - }, + } ); this.ensureBlankLine(); @@ -866,7 +866,7 @@ export class PhpRenderer extends ConvenienceRenderer { " * @return stdClass\n", " * @throws Exception\n", " */\n", - "public function to(): stdClass ", + "public function to(): stdClass " ], () => { this.emitLine("$out = new stdClass();"); @@ -875,7 +875,7 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine("$out->{'", jsonName, "'} = $this->", names.to, "();"); }); this.emitLine("return $out;"); - }, + } ); this.ensureBlankLine(); @@ -889,7 +889,7 @@ export class PhpRenderer extends ConvenienceRenderer { " * @throws Exception\n", " */\n", "public static function from(stdClass $obj): ", - className, + className ], () => { if (this._options.fastGet) { @@ -907,7 +907,7 @@ export class PhpRenderer extends ConvenienceRenderer { comma = ","; }); this.emitLine(");"); - }, + } ); this.ensureBlankLine(); this.emitBlock( @@ -921,33 +921,33 @@ export class PhpRenderer extends ConvenienceRenderer { comma = ","; }); this.emitLine(");"); - }, + } ); }); this.finishFile(); } - protected emitUnionAttributes (_u: UnionType, _unionName: Name): void { + protected emitUnionAttributes(_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionSerializer (_u: UnionType, _unionName: Name): void { + protected emitUnionSerializer(_u: UnionType, _unionName: Name): void { // empty } - protected emitUnionDefinition (_u: UnionType, _unionName: Name): void { + protected emitUnionDefinition(_u: UnionType, _unionName: Name): void { throw Error("emitUnionDefinition not implemented"); } - protected emitEnumSerializationAttributes (_e: EnumType) { + protected emitEnumSerializationAttributes(_e: EnumType) { // Empty } - protected emitEnumDeserializationAttributes (_e: EnumType) { + protected emitEnumDeserializationAttributes(_e: EnumType) { // Empty } - protected emitEnumDefinition (e: EnumType, enumName: Name): void { + protected emitEnumDefinition(e: EnumType, enumName: Name): void { this.emitFileHeader(enumName, []); this.emitDescription(this.descriptionForType(e)); const caseNames: Sourcelike[] = []; @@ -986,7 +986,7 @@ export class PhpRenderer extends ConvenienceRenderer { "public static function to(", enumName, " $obj): ", - enumSerdeType, + enumSerdeType ], () => { this.emitLine("switch ($obj->enum) {"); @@ -1000,13 +1000,13 @@ export class PhpRenderer extends ConvenienceRenderer { name, "->enum: return '", stringEscape(jsonName), - "';", + "';" ); }); }); this.emitLine("}"); this.emitLine("throw new Exception('the give value is not an enum-value.');"); - }, + } ); this.ensureBlankLine(); this.emitEnumDeserializationAttributes(e); @@ -1021,7 +1021,7 @@ export class PhpRenderer extends ConvenienceRenderer { " * @throws Exception\n", " */\n", "public static function from($obj): ", - enumName, + enumName ], () => { this.emitLine("switch ($obj) {"); @@ -1032,8 +1032,8 @@ export class PhpRenderer extends ConvenienceRenderer { }); }); this.emitLine("}"); - this.emitLine("throw new Exception(\"Cannot deserialize ", enumName, "\");"); - }, + this.emitLine('throw new Exception("Cannot deserialize ', enumName, '");'); + } ); this.ensureBlankLine(); this.emitBlock( @@ -1044,20 +1044,20 @@ export class PhpRenderer extends ConvenienceRenderer { lines.push([enumName, "::$", name]); }); this.emitLine("return ", lines[0], ";"); - }, + } ); }); this.emitLine(enumName, "::init();"); this.finishFile(); } - protected emitSourceStructure (givenFilename: string): void { + protected emitSourceStructure(givenFilename: string): void { this.emitLine(" this.emitClassDefinition(c, n), (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n), + (u, n) => this.emitUnionDefinition(u, n) ); if (this._options.withClosing) { this.emitLine("?>"); diff --git a/packages/quicktype-core/src/language/Pike.ts b/packages/quicktype-core/src/language/Pike.ts index 0e9716278..637bedcac 100644 --- a/packages/quicktype-core/src/language/Pike.ts +++ b/packages/quicktype-core/src/language/Pike.ts @@ -1,13 +1,13 @@ import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { type Option } from "../RendererOptions"; import { type RenderContext } from "../Renderer"; -import { type MultiWord, type Sourcelike} from "../Source"; +import { type MultiWord, type Sourcelike } from "../Source"; import { multiWord, parenIfNeeded, singleWord } from "../Source"; import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type ClassType, type EnumType, type UnionType} from "../Type"; +import { type Type, type ClassType, type EnumType, type UnionType } from "../Type"; import { ArrayType, MapType, PrimitiveType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; import { legalizeCharacters, isLetterOrUnderscoreOrDigit, stringEscape, makeNameStyle } from "../support/Strings"; @@ -66,7 +66,7 @@ const keywords = [ "sscanf", "switch", "typeof", - "global", + "global" ]; const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); @@ -75,21 +75,21 @@ const namingFunction = funPrefixNamer("genericNamer", makeNameStyle("underscore" const namedTypeNamingFunction = funPrefixNamer("typeNamer", makeNameStyle("pascal", legalizeName)); export class PikeTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Pike", ["pike", "pikelang"], "pmod"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return []; } - protected makeRenderer (renderContext: RenderContext): PikeRenderer { + protected makeRenderer(renderContext: RenderContext): PikeRenderer { return new PikeRenderer(this, renderContext); } } export class PikeRenderer extends ConvenienceRenderer { - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { this.emitInformationComment(); this.ensureBlankLine(); this.forEachTopLevel( @@ -100,54 +100,54 @@ export class PikeRenderer extends ConvenienceRenderer { this.emitTopLevelConverter(t, name); this.ensureBlankLine(); }, - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); this.ensureBlankLine(); this.forEachNamedType( "leading-and-interposing", (c: ClassType, className: Name) => this.emitClassDefinition(c, className), (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n), + (u, n) => this.emitUnion(u, n) ); } - protected get enumCasesInGlobalNamespace (): boolean { + protected get enumCasesInGlobalNamespace(): boolean { return true; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return enumNamingFunction; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return namedTypeNamingFunction; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return namingFunction; } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return namingFunction; } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return [...keywords]; } - protected forbiddenForObjectProperties (_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected sourceFor (t: Type): MultiWord { + protected sourceFor(t: Type): MultiWord { if (["class", "object", "enum"].includes(t.kind)) { return singleWord(this.nameForNamedType(t)); } @@ -177,11 +177,11 @@ export class PikeRenderer extends ConvenienceRenderer { } else { return singleWord(this.nameForNamedType(unionType)); } - }, + } ); } - protected emitClassDefinition (c: ClassType, className: Name): void { + protected emitClassDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitBlock(["class ", className], () => { this.emitClassMembers(c); @@ -192,20 +192,20 @@ export class PikeRenderer extends ConvenienceRenderer { this.emitDecodingFunction(className, c); } - protected emitEnum (e: EnumType, enumName: Name): void { + protected emitEnum(e: EnumType, enumName: Name): void { this.emitBlock([e.kind, " ", enumName], () => { let table: Sourcelike[][] = []; this.forEachEnumCase(e, "none", (name, jsonName) => { table.push([ - [name, " = \"", stringEscape(jsonName), "\", "], - ["// json: \"", jsonName, "\""], + [name, ' = "', stringEscape(jsonName), '", '], + ['// json: "', jsonName, '"'] ]); }); this.emitTable(table); }); } - protected emitUnion (u: UnionType, unionName: Name): void { + protected emitUnion(u: UnionType, unionName: Name): void { const isMaybeWithSingleType = nullableFromUnion(u); if (isMaybeWithSingleType !== null) { @@ -227,7 +227,7 @@ export class PikeRenderer extends ConvenienceRenderer { types.map(r => r.map(sl => this.sourcelikeToString(sl))).join("|"), " ", unionName, - ";", + ";" ]); this.ensureBlankLine(); this.emitBlock([unionName, " ", unionName, "_from_JSON(mixed json)"], () => { @@ -235,17 +235,17 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitBlock (line: Sourcelike, f: () => void, opening: Sourcelike = " {", closing: Sourcelike = "}"): void { + private emitBlock(line: Sourcelike, f: () => void, opening: Sourcelike = " {", closing: Sourcelike = "}"): void { this.emitLine(line, opening); this.indent(f); this.emitLine(closing); } - private emitMappingBlock (line: Sourcelike, f: () => void): void { + private emitMappingBlock(line: Sourcelike, f: () => void): void { this.emitBlock(line, f, "([", "]);"); } - private emitClassMembers (c: ClassType): void { + private emitClassMembers(c: ClassType): void { let table: Sourcelike[][] = []; this.forEachClassProperty(c, "none", (name, jsonName, p) => { const pikeType = this.sourceFor(p.type).source; @@ -253,13 +253,13 @@ export class PikeRenderer extends ConvenienceRenderer { table.push([ [pikeType, " "], [name, "; "], - ["// json: \"", jsonName, "\""], + ['// json: "', jsonName, '"'] ]); }); this.emitTable(table); } - private emitInformationComment () { + private emitInformationComment() { this.emitCommentLines( [ "This source has been automatically generated by quicktype.", @@ -274,17 +274,17 @@ export class PikeRenderer extends ConvenienceRenderer { "It will return an instance of .", "Bear in mind that these functions have unexpected behavior,", "and will likely throw an error, if the JSON string does not", - "match the expected interface, even if the JSON itself is valid.", + "match the expected interface, even if the JSON itself is valid." ], - { lineStart: "// " }, + { lineStart: "// " } ); } - private emitTopLevelTypedef (t: Type, name: Name) { + private emitTopLevelTypedef(t: Type, name: Name) { this.emitLine("typedef ", this.sourceFor(t).source, " ", name, ";"); } - private emitTopLevelConverter (t: Type, name: Name) { + private emitTopLevelConverter(t: Type, name: Name) { this.emitBlock([name, " ", name, "_from_JSON(mixed json)"], () => { if (t instanceof PrimitiveType) { this.emitLine(["return json;"]); @@ -305,11 +305,11 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitEncodingFunction (c: ClassType) { + private emitEncodingFunction(c: ClassType) { this.emitBlock(["string encode_json()"], () => { this.emitMappingBlock(["mapping(string:mixed) json = "], () => { this.forEachClassProperty(c, "none", (name, jsonName) => { - this.emitLine(["\"", stringEscape(jsonName), "\" : ", name, ","]); + this.emitLine(['"', stringEscape(jsonName), '" : ', name, ","]); }); }); this.ensureBlankLine(); @@ -317,12 +317,12 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitDecodingFunction (className: Name, c: ClassType) { + private emitDecodingFunction(className: Name, c: ClassType) { this.emitBlock([className, " ", className, "_from_JSON(mixed json)"], () => { this.emitLine([className, " retval = ", className, "();"]); this.ensureBlankLine(); this.forEachClassProperty(c, "none", (name, jsonName) => { - this.emitLine(["retval.", name, " = json[\"", stringEscape(jsonName), "\"];"]); + this.emitLine(["retval.", name, ' = json["', stringEscape(jsonName), '"];']); }); this.ensureBlankLine(); this.emitLine(["return retval;"]); diff --git a/packages/quicktype-core/src/language/Python.ts b/packages/quicktype-core/src/language/Python.ts index 91cb653e4..5edc549b2 100644 --- a/packages/quicktype-core/src/language/Python.ts +++ b/packages/quicktype-core/src/language/Python.ts @@ -1,22 +1,13 @@ import { TargetLanguage } from "../TargetLanguage"; import { type StringTypeMapping } from "../TypeBuilder"; -import { - type TransformedStringTypeKind, - type PrimitiveStringTypeKind, - type Type, - type ClassProperty, -} from "../Type"; -import { - EnumType, - ClassType, - UnionType, -} from "../Type"; +import { type TransformedStringTypeKind, type PrimitiveStringTypeKind, type Type, type ClassProperty } from "../Type"; +import { EnumType, ClassType, UnionType } from "../Type"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { getOptionValues, EnumOption, BooleanOption } from "../RendererOptions"; -import { type ForbiddenWordsInfo} from "../ConvenienceRenderer"; +import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; import { ConvenienceRenderer, topLevelNameOrder } from "../ConvenienceRenderer"; -import { type Namer, type Name} from "../Naming"; +import { type Namer, type Name } from "../Naming"; import { funPrefixNamer, DependencyName } from "../Naming"; import { splitIntoWords, @@ -26,14 +17,13 @@ import { allUpperWordStyle, allLowerWordStyle, stringEscape, - originalWord, + originalWord } from "../support/Strings"; import { assertNever, panic, defined } from "../support/Support"; -import { type Sourcelike, type MultiWord} from "../Source"; +import { type Sourcelike, type MultiWord } from "../Source"; import { multiWord, singleWord, parenIfNeeded, modifySource } from "../Source"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { - type Transformer} from "../Transformers"; +import { type Transformer } from "../Transformers"; import { followTargetType, transformationForType, @@ -44,7 +34,7 @@ import { ParseStringTransformer, UnionMemberMatchTransformer, StringifyTransformer, - EncodingTransformer, + EncodingTransformer } from "../Transformers"; import { arrayIntercalate, @@ -52,7 +42,7 @@ import { mapUpdateInto, iterableSome, mapSortBy, - iterableFirst, + iterableFirst } from "collection-utils"; import unicode from "unicode-properties"; @@ -71,7 +61,7 @@ const forbiddenTypeNames = [ "Type", "TypeVar", "T", - "EnumT", + "EnumT" ]; const forbiddenPropertyNames = [ "and", @@ -113,7 +103,7 @@ const forbiddenPropertyNames = [ "try", "while", "with", - "yield", + "yield" ]; export interface PythonFeatures { @@ -128,20 +118,20 @@ export const pythonOptions = { [ ["3.5", { typeHints: false, dataClasses: false }], ["3.6", { typeHints: true, dataClasses: false }], - ["3.7", { typeHints: true, dataClasses: true }], + ["3.7", { typeHints: true, dataClasses: true }] ], - "3.6", + "3.6" ), justTypes: new BooleanOption("just-types", "Classes only", false), - nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be Pythonic", true), + nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be Pythonic", true) }; export class PythonTargetLanguage extends TargetLanguage { - protected getOptions (): Array> { + protected getOptions(): Array> { return [pythonOptions.features, pythonOptions.justTypes, pythonOptions.nicePropertyNames]; } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); @@ -153,15 +143,15 @@ export class PythonTargetLanguage extends TargetLanguage { return mapping; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return false; } - needsTransformerForType (t: Type): boolean { + public needsTransformerForType(t: Type): boolean { if (t instanceof UnionType) { return iterableSome(t.members, m => this.needsTransformerForType(m)); } @@ -169,7 +159,7 @@ export class PythonTargetLanguage extends TargetLanguage { return t.kind === "integer-string" || t.kind === "bool-string"; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): PythonRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): PythonRenderer { const options = getOptionValues(pythonOptions, untypedOptionValues); if (options.justTypes) { return new PythonRenderer(this, renderContext, options); @@ -179,20 +169,20 @@ export class PythonTargetLanguage extends TargetLanguage { } } -function isNormalizedStartCharacter3 (utf16Unit: number): boolean { +function isNormalizedStartCharacter3(utf16Unit: number): boolean { // FIXME: add Other_ID_Start - https://docs.python.org/3/reference/lexical_analysis.html#identifiers const category: string = unicode.getCategory(utf16Unit); return ["Lu", "Ll", "Lt", "Lm", "Lo", "Nl"].includes(category); } -function isNormalizedPartCharacter3 (utf16Unit: number): boolean { +function isNormalizedPartCharacter3(utf16Unit: number): boolean { // FIXME: add Other_ID_Continue - https://docs.python.org/3/reference/lexical_analysis.html#identifiers if (isNormalizedStartCharacter3(utf16Unit)) return true; const category: string = unicode.getCategory(utf16Unit); return ["Mn", "Mc", "Nd", "Pc"].includes(category); } -function isStartCharacter3 (utf16Unit: number): boolean { +function isStartCharacter3(utf16Unit: number): boolean { const s = String.fromCharCode(utf16Unit).normalize("NFKC"); const l = s.length; if (l === 0 || !isNormalizedStartCharacter3(s.charCodeAt(0))) return false; @@ -203,7 +193,7 @@ function isStartCharacter3 (utf16Unit: number): boolean { return true; } -function isPartCharacter3 (utf16Unit: number): boolean { +function isPartCharacter3(utf16Unit: number): boolean { const s = String.fromCharCode(utf16Unit).normalize("NFKC"); const l = s.length; for (let i = 0; i < l; i++) { @@ -215,7 +205,7 @@ function isPartCharacter3 (utf16Unit: number): boolean { const legalizeName3 = utf16LegalizeCharacters(isPartCharacter3); -function classNameStyle (original: string): string { +function classNameStyle(original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -225,11 +215,11 @@ function classNameStyle (original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter3, + isStartCharacter3 ); } -function getWordStyle (uppercase: boolean, forceSnakeNameStyle: boolean) { +function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean) { if (!forceSnakeNameStyle) { return originalWord; } @@ -237,7 +227,7 @@ function getWordStyle (uppercase: boolean, forceSnakeNameStyle: boolean) { return uppercase ? allUpperWordStyle : allLowerWordStyle; } -function snakeNameStyle (original: string, uppercase: boolean, forceSnakeNameStyle: boolean): string { +function snakeNameStyle(original: string, uppercase: boolean, forceSnakeNameStyle: boolean): string { const wordStyle = getWordStyle(uppercase, forceSnakeNameStyle); const separator = forceSnakeNameStyle ? "_" : ""; const words = splitIntoWords(original); @@ -249,103 +239,103 @@ export class PythonRenderer extends ConvenienceRenderer { private readonly declaredTypes: Set = new Set(); - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly pyOptions: OptionValues, + protected readonly pyOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return forbiddenTypeNames; } - protected forbiddenForObjectProperties (_: ClassType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_: ClassType, _classNamed: Name): ForbiddenWordsInfo { return { names: forbiddenPropertyNames, includeGlobalForbidden: false }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("type", classNameStyle); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return funPrefixNamer("property", s => snakeNameStyle(s, false, this.pyOptions.nicePropertyNames)); } - protected makeUnionMemberNamer (): null { + protected makeUnionMemberNamer(): null { return null; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("enum-case", s => snakeNameStyle(s, true, this.pyOptions.nicePropertyNames)); } - protected get commentLineStart (): string { + protected get commentLineStart(): string { return "# "; } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { if (lines.length === 1) { const docstring = modifySource(content => { - if (content.endsWith("\"")) { - return content.slice(0, -1) + "\\\""; + if (content.endsWith('"')) { + return content.slice(0, -1) + '\\"'; } return content; }, lines[0]); - this.emitComments([{ customLines: [docstring], lineStart: "\"\"\"", lineEnd: "\"\"\"" }]); + this.emitComments([{ customLines: [docstring], lineStart: '"""', lineEnd: '"""' }]); } else { this.emitCommentLines(lines, { - firstLineStart: "\"\"\"", + firstLineStart: '"""', lineStart: "", - afterComment: "\"\"\"", + afterComment: '"""' }); } } - protected get needsTypeDeclarationBeforeUse (): boolean { + protected get needsTypeDeclarationBeforeUse(): boolean { return true; } - protected canBeForwardDeclared (t: Type): boolean { + protected canBeForwardDeclared(t: Type): boolean { const kind = t.kind; return kind === "class" || kind === "enum"; } - protected emitBlock (line: Sourcelike, f: () => void): void { + protected emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line); this.indent(f); } - protected string (s: string): Sourcelike { - const openQuote = "\""; - return [openQuote, stringEscape(s), "\""]; + protected string(s: string): Sourcelike { + const openQuote = '"'; + return [openQuote, stringEscape(s), '"']; } - protected withImport (module: string, name: string): Sourcelike { + protected withImport(module: string, name: string): Sourcelike { if (this.pyOptions.features.typeHints || module !== "typing") { // FIXME: This is ugly. We should rather not generate that import in the first // place, but right now we just make the type source and then throw it away. It's // not a performance issue, so it's fine, I just bemoan this special case, and // potential others down the road. - mapUpdateInto(this.imports, module, s => s ? setUnionInto(s, [name]) : new Set([name])); + mapUpdateInto(this.imports, module, s => (s ? setUnionInto(s, [name]) : new Set([name]))); } return name; } - protected withTyping (name: string): Sourcelike { + protected withTyping(name: string): Sourcelike { return this.withImport("typing", name); } - protected namedType (t: Type): Sourcelike { + protected namedType(t: Type): Sourcelike { const name = this.nameForNamedType(t); if (this.declaredTypes.has(t)) return name; return ["'", name, "'"]; } - protected pythonType (t: Type, _isRootTypeDef = false): Sourcelike { + protected pythonType(t: Type, _isRootTypeDef = false): Sourcelike { const actualType = followTargetType(t); return matchType( @@ -380,7 +370,7 @@ export class PythonRenderer extends ConvenienceRenderer { "[Union[", arrayIntercalate(", ", memberTypes), "]]", - ...rest, + ...rest ]; } else { return [this.withTyping("Optional"), "[", defined(iterableFirst(memberTypes)), "]", ...rest]; @@ -399,11 +389,11 @@ export class PythonRenderer extends ConvenienceRenderer { } return panic(`Transformed type ${transformedStringType.kind} not supported`); - }, + } ); } - protected declarationLine (t: Type): Sourcelike { + protected declarationLine(t: Type): Sourcelike { if (t instanceof ClassType) { return ["class ", this.nameForNamedType(t), ":"]; } @@ -423,7 +413,7 @@ export class PythonRenderer extends ConvenienceRenderer { this.declaredTypes.add(t); } - protected emitClassMembers (t: ClassType): void { + protected emitClassMembers(t: ClassType): void { if (this.pyOptions.features.dataClasses) return; const args: Sourcelike[] = []; @@ -440,11 +430,11 @@ export class PythonRenderer extends ConvenienceRenderer { this.emitLine("self.", name, " = ", name); }); } - }, + } ); } - protected typeHint (...sl: Sourcelike[]): Sourcelike { + protected typeHint(...sl: Sourcelike[]): Sourcelike { if (this.pyOptions.features.typeHints) { return sl; } @@ -452,28 +442,28 @@ export class PythonRenderer extends ConvenienceRenderer { return []; } - protected typingDecl (name: Sourcelike, type: string): Sourcelike { + protected typingDecl(name: Sourcelike, type: string): Sourcelike { return [name, this.typeHint(": ", this.withTyping(type))]; } - protected typingReturn (type: string): Sourcelike { + protected typingReturn(type: string): Sourcelike { return this.typeHint(" -> ", this.withTyping(type)); } - protected sortClassProperties ( + protected sortClassProperties( properties: ReadonlyMap, - propertyNames: ReadonlyMap, + propertyNames: ReadonlyMap ): ReadonlyMap { if (this.pyOptions.features.dataClasses) { return mapSortBy(properties, (p: ClassProperty) => { - return p.type instanceof UnionType && nullableFromUnion(p.type) != null || p.isOptional ? 1 : 0; + return (p.type instanceof UnionType && nullableFromUnion(p.type) != null) || p.isOptional ? 1 : 0; }); } else { return super.sortClassProperties(properties, propertyNames); } } - protected emitClass (t: ClassType): void { + protected emitClass(t: ClassType): void { if (this.pyOptions.features.dataClasses) { this.emitLine("@", this.withImport("dataclasses", "dataclass")); } @@ -496,7 +486,7 @@ export class PythonRenderer extends ConvenienceRenderer { }); } - protected emitEnum (t: EnumType): void { + protected emitEnum(t: EnumType): void { this.declareType(t, () => { this.forEachEnumCase(t, "none", (name, jsonName) => { this.emitLine([name, " = ", this.string(jsonName)]); @@ -504,21 +494,21 @@ export class PythonRenderer extends ConvenienceRenderer { }); } - protected emitImports (): void { + protected emitImports(): void { this.imports.forEach((names, module) => { this.emitLine("from ", module, " import ", Array.from(names).join(", ")); }); } - protected emitSupportCode (): void { + protected emitSupportCode(): void { return; } - protected emitClosingCode (): void { + protected emitClosingCode(): void { return; } - protected emitSourceStructure (_givenOutputFilename: string): void { + protected emitSourceStructure(_givenOutputFilename: string): void { const declarationLines = this.gatherSource(() => { this.forEachNamedType( ["interposing", 2], @@ -526,7 +516,7 @@ export class PythonRenderer extends ConvenienceRenderer { e => this.emitEnum(e), _u => { return; - }, + } ); }); @@ -586,9 +576,9 @@ export interface ValueOrLambda { // // * If `input` is a value, the result is `f(input)`. // * If `input` is a lambda, the result is `lambda x: f(input(x))` -function compose (input: ValueOrLambda, f: (arg: Sourcelike) => Sourcelike): ValueOrLambda; -function compose (input: ValueOrLambda, f: ValueOrLambda): ValueOrLambda; -function compose (input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => Sourcelike)): ValueOrLambda { +function compose(input: ValueOrLambda, f: (arg: Sourcelike) => Sourcelike): ValueOrLambda; +function compose(input: ValueOrLambda, f: ValueOrLambda): ValueOrLambda; +function compose(input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => Sourcelike)): ValueOrLambda { if (typeof f === "function") { if (input.value !== undefined) { // `input` is a value, so just apply `f` to its source form. @@ -623,7 +613,7 @@ function compose (input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => // `input` is a lambda, so the result is `lambda x: f(input(x))`. return { lambda: multiWord("", "lambda x: ", parenIfNeeded(f.lambda), "(", parenIfNeeded(input.lambda), "(x))"), - value: undefined, + value: undefined }; } @@ -635,7 +625,7 @@ const identity: ValueOrLambda = { value: undefined }; // If `vol` is a lambda, return it in its source form. If it's // a value, return a `lambda` that returns the value. -function makeLambda (vol: ValueOrLambda): MultiWord { +function makeLambda(vol: ValueOrLambda): MultiWord { if (vol.lambda !== undefined) { if (vol.value === undefined) { return vol.lambda; @@ -651,7 +641,7 @@ function makeLambda (vol: ValueOrLambda): MultiWord { // If `vol` is a value, return the value in its source form. // Calling this with `vol` being a lambda is not allowed. -function makeValue (vol: ValueOrLambda): Sourcelike { +function makeValue(vol: ValueOrLambda): Sourcelike { if (vol.value === undefined) { return panic("Cannot make value from lambda without value"); } @@ -667,7 +657,7 @@ export class JSONPythonRenderer extends PythonRenderer { private readonly _deserializerFunctions = new Set(); private readonly _converterNamer = funPrefixNamer("converter", s => - snakeNameStyle(s, false, this.pyOptions.nicePropertyNames), + snakeNameStyle(s, false, this.pyOptions.nicePropertyNames) ); private readonly _topLevelConverterNames = new Map(); @@ -678,7 +668,7 @@ export class JSONPythonRenderer extends PythonRenderer { private _haveDateutil = false; - protected emitTypeVar (tvar: string, constraints: Sourcelike): void { + protected emitTypeVar(tvar: string, constraints: Sourcelike): void { if (!this.pyOptions.features.typeHints) { return; } @@ -686,7 +676,7 @@ export class JSONPythonRenderer extends PythonRenderer { this.emitLine(tvar, " = ", this.withTyping("TypeVar"), "(", this.string(tvar), constraints, ")"); } - protected typeVar (): string { + protected typeVar(): string { this._haveTypeVar = true; // FIXME: This is ugly, but the code that requires the type variables, in // `emitImports` actually runs after imports have been imported. The proper @@ -698,7 +688,7 @@ export class JSONPythonRenderer extends PythonRenderer { return "T"; } - protected enumTypeVar (): string { + protected enumTypeVar(): string { this._haveEnumTypeVar = true; // See the comment above. this.withTyping("TypeVar"); @@ -706,7 +696,7 @@ export class JSONPythonRenderer extends PythonRenderer { return "EnumT"; } - protected cast (type: Sourcelike, v: Sourcelike): Sourcelike { + protected cast(type: Sourcelike, v: Sourcelike): Sourcelike { if (!this.pyOptions.features.typeHints) { return v; } @@ -714,7 +704,7 @@ export class JSONPythonRenderer extends PythonRenderer { return [this.withTyping("cast"), "(", type, ", ", v, ")"]; } - protected emitNoneConverter (): void { + protected emitNoneConverter(): void { // FIXME: We can't return the None type here because mypy thinks that means // We're not returning any value, when we're actually returning `None`. this.emitBlock( @@ -722,39 +712,39 @@ export class JSONPythonRenderer extends PythonRenderer { () => { this.emitLine("assert x is None"); this.emitLine("return x"); - }, + } ); } - protected emitBoolConverter (): void { + protected emitBoolConverter(): void { this.emitBlock(["def from_bool(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> bool"), ":"], () => { this.emitLine("assert isinstance(x, bool)"); this.emitLine("return x"); }); } - protected emitIntConverter (): void { + protected emitIntConverter(): void { this.emitBlock(["def from_int(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> int"), ":"], () => { this.emitLine("assert isinstance(x, int) and not isinstance(x, bool)"); this.emitLine("return x"); }); } - protected emitFromFloatConverter (): void { + protected emitFromFloatConverter(): void { this.emitBlock(["def from_float(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> float"), ":"], () => { this.emitLine("assert isinstance(x, (float, int)) and not isinstance(x, bool)"); this.emitLine("return float(x)"); }); } - protected emitToFloatConverter (): void { + protected emitToFloatConverter(): void { this.emitBlock(["def to_float(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> float"), ":"], () => { this.emitLine("assert isinstance(x, float)"); this.emitLine("return x"); }); } - protected emitStrConverter (): void { + protected emitStrConverter(): void { this.emitBlock(["def from_str(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> str"), ":"], () => { const strType = "str"; this.emitLine("assert isinstance(x, ", strType, ")"); @@ -762,7 +752,7 @@ export class JSONPythonRenderer extends PythonRenderer { }); } - protected emitToEnumConverter (): void { + protected emitToEnumConverter(): void { const tvar = this.enumTypeVar(); this.emitBlock( [ @@ -772,16 +762,16 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", tvar), - ":", + ":" ], () => { this.emitLine("assert isinstance(x, c)"); this.emitLine("return x.value"); - }, + } ); } - protected emitListConverter (): void { + protected emitListConverter(): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -791,16 +781,16 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withTyping("List"), "[", tvar, "]"), - ":", + ":" ], () => { this.emitLine("assert isinstance(x, list)"); this.emitLine("return [f(y) for y in x]"); - }, + } ); } - protected emitToClassConverter (): void { + protected emitToClassConverter(): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -810,16 +800,16 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> dict"), - ":", + ":" ], () => { this.emitLine("assert isinstance(x, c)"); this.emitLine("return ", this.cast(this.withTyping("Any"), "x"), ".to_dict()"); - }, + } ); } - protected emitDictConverter (): void { + protected emitDictConverter(): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -829,18 +819,18 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withTyping("Dict"), "[str, ", tvar, "]"), - ":", + ":" ], () => { this.emitLine("assert isinstance(x, dict)"); this.emitLine("return { k: f(v) for (k, v) in x.items() }"); - }, + } ); } // This is not easily idiomatically typeable in Python. See // https://stackoverflow.com/questions/51066468/computed-types-in-mypy/51084497 - protected emitUnionConverter (): void { + protected emitUnionConverter(): void { this.emitMultiline(`def from_union(fs, x): for f in fs: try: @@ -850,34 +840,34 @@ export class JSONPythonRenderer extends PythonRenderer { assert False`); } - protected emitFromDatetimeConverter (): void { + protected emitFromDatetimeConverter(): void { this.emitBlock( [ "def from_datetime(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withImport("datetime", "datetime")), - ":", + ":" ], () => { this._haveDateutil = true; this.emitLine("return dateutil.parser.parse(x)"); - }, + } ); } - protected emitFromStringifiedBoolConverter (): void { + protected emitFromStringifiedBoolConverter(): void { this.emitBlock( ["def from_stringified_bool(x", this.typeHint(": str"), ")", this.typeHint(" -> bool"), ":"], () => { - this.emitBlock("if x == \"true\":", () => this.emitLine("return True")); - this.emitBlock("if x == \"false\":", () => this.emitLine("return False")); + this.emitBlock('if x == "true":', () => this.emitLine("return True")); + this.emitBlock('if x == "false":', () => this.emitLine("return False")); this.emitLine("assert False"); - }, + } ); } - protected emitIsTypeConverter (): void { + protected emitIsTypeConverter(): void { const tvar = this.typeVar(); this.emitBlock( [ @@ -887,58 +877,86 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", tvar), - ":", + ":" ], () => { this.emitLine("assert isinstance(x, t)"); this.emitLine("return x"); - }, + } ); } - protected emitConverter (cf: ConverterFunction): void { + protected emitConverter(cf: ConverterFunction): void { switch (cf) { - case "none": - { this.emitNoneConverter(); return; } + case "none": { + this.emitNoneConverter(); + return; + } - case "bool": - { this.emitBoolConverter(); return; } + case "bool": { + this.emitBoolConverter(); + return; + } - case "int": - { this.emitIntConverter(); return; } + case "int": { + this.emitIntConverter(); + return; + } - case "from-float": - { this.emitFromFloatConverter(); return; } + case "from-float": { + this.emitFromFloatConverter(); + return; + } - case "to-float": - { this.emitToFloatConverter(); return; } + case "to-float": { + this.emitToFloatConverter(); + return; + } - case "str": - { this.emitStrConverter(); return; } + case "str": { + this.emitStrConverter(); + return; + } - case "to-enum": - { this.emitToEnumConverter(); return; } + case "to-enum": { + this.emitToEnumConverter(); + return; + } - case "list": - { this.emitListConverter(); return; } + case "list": { + this.emitListConverter(); + return; + } - case "to-class": - { this.emitToClassConverter(); return; } + case "to-class": { + this.emitToClassConverter(); + return; + } - case "dict": - { this.emitDictConverter(); return; } + case "dict": { + this.emitDictConverter(); + return; + } - case "union": - { this.emitUnionConverter(); return; } + case "union": { + this.emitUnionConverter(); + return; + } - case "from-datetime": - { this.emitFromDatetimeConverter(); return; } + case "from-datetime": { + this.emitFromDatetimeConverter(); + return; + } - case "from-stringified-bool": - { this.emitFromStringifiedBoolConverter(); return; } + case "from-stringified-bool": { + this.emitFromStringifiedBoolConverter(); + return; + } - case "is-type": - { this.emitIsTypeConverter(); return; } + case "is-type": { + this.emitIsTypeConverter(); + return; + } default: return assertNever(cf); @@ -946,7 +964,7 @@ export class JSONPythonRenderer extends PythonRenderer { } // Return the name of the Python converter function `cf`. - protected conv (cf: ConverterFunction): Sourcelike { + protected conv(cf: ConverterFunction): Sourcelike { this._deserializerFunctions.add(cf); const name = cf.replace(/-/g, "_"); if (cf.startsWith("from-") || cf.startsWith("to-") || cf.startsWith("is-")) return name; @@ -954,11 +972,11 @@ export class JSONPythonRenderer extends PythonRenderer { } // Applies the converter function to `arg` - protected convFn (cf: ConverterFunction, arg: ValueOrLambda): ValueOrLambda { + protected convFn(cf: ConverterFunction, arg: ValueOrLambda): ValueOrLambda { return compose(arg, { lambda: singleWord(this.conv(cf)), value: undefined }); } - protected typeObject (t: Type): Sourcelike { + protected typeObject(t: Type): Sourcelike { const s = matchType( t, _anyType => undefined, @@ -982,7 +1000,7 @@ export class JSONPythonRenderer extends PythonRenderer { } return undefined; - }, + } ); if (s === undefined) { return panic(`No type object for ${t.kind}`); @@ -991,7 +1009,7 @@ export class JSONPythonRenderer extends PythonRenderer { return s; } - protected transformer (inputTransformer: ValueOrLambda, xfer: Transformer, targetType: Type): ValueOrLambda { + protected transformer(inputTransformer: ValueOrLambda, xfer: Transformer, targetType: Type): ValueOrLambda { const consume = (consumer: Transformer | undefined, vol: ValueOrLambda) => { if (consumer === undefined) { return vol; @@ -1012,7 +1030,7 @@ export class JSONPythonRenderer extends PythonRenderer { arrayIntercalate(", ", lambdas), "], ", v, - ")", + ")" ]); } else if (xfer instanceof DecodingTransformer) { const consumer = xfer.consumer; @@ -1083,7 +1101,7 @@ export class JSONPythonRenderer extends PythonRenderer { // Returns the code to deserialize `value` as type `t`. If `t` has // an associated transformer, the code for that transformer is // returned. - protected deserializer (value: ValueOrLambda, t: Type): ValueOrLambda { + protected deserializer(value: ValueOrLambda, t: Type): ValueOrLambda { const xf = transformationForType(t); if (xf !== undefined) { return this.transformer(value, xf.transformer, xf.targetType); @@ -1104,12 +1122,12 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.deserializer(identity, arrayType.items)).source, ", ", v, - ")", + ")" ]), classType => compose(value, { lambda: singleWord(this.nameForNamedType(classType), ".from_dict"), - value: undefined, + value: undefined }), mapType => compose(value, v => [ @@ -1118,13 +1136,13 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.deserializer(identity, mapType.values)).source, ", ", v, - ")", + ")" ]), enumType => compose(value, { lambda: singleWord(this.nameForNamedType(enumType)), value: undefined }), unionType => { // FIXME: handle via transformers const deserializers = Array.from(unionType.members).map( - m => makeLambda(this.deserializer(identity, m)).source, + m => makeLambda(this.deserializer(identity, m)).source ); return compose(value, v => [ this.conv("union"), @@ -1132,7 +1150,7 @@ export class JSONPythonRenderer extends PythonRenderer { arrayIntercalate(", ", deserializers), "], ", v, - ")", + ")" ]); }, transformedStringType => { @@ -1146,11 +1164,11 @@ export class JSONPythonRenderer extends PythonRenderer { } return panic(`Transformed type ${transformedStringType.kind} not supported`); - }, + } ); } - protected serializer (value: ValueOrLambda, t: Type): ValueOrLambda { + protected serializer(value: ValueOrLambda, t: Type): ValueOrLambda { const xf = transformationForType(t); if (xf !== undefined) { const reverse = xf.reverse; @@ -1172,7 +1190,7 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.serializer(identity, arrayType.items)).source, ", ", v, - ")", + ")" ]), classType => compose(value, v => [this.conv("to-class"), "(", this.nameForNamedType(classType), ", ", v, ")"]), @@ -1183,12 +1201,12 @@ export class JSONPythonRenderer extends PythonRenderer { makeLambda(this.serializer(identity, mapType.values)).source, ", ", v, - ")", + ")" ]), enumType => compose(value, v => [this.conv("to-enum"), "(", this.nameForNamedType(enumType), ", ", v, ")"]), unionType => { const serializers = Array.from(unionType.members).map( - m => makeLambda(this.serializer(identity, m)).source, + m => makeLambda(this.serializer(identity, m)).source ); return compose(value, v => [ this.conv("union"), @@ -1196,7 +1214,7 @@ export class JSONPythonRenderer extends PythonRenderer { arrayIntercalate(", ", serializers), "], ", v, - ")", + ")" ]); }, transformedStringType => { @@ -1209,11 +1227,11 @@ export class JSONPythonRenderer extends PythonRenderer { } return panic(`Transformed type ${transformedStringType.kind} not supported`); - }, + } ); } - protected emitClassMembers (t: ClassType): void { + protected emitClassMembers(t: ClassType): void { super.emitClassMembers(t); this.ensureBlankLine(); @@ -1231,7 +1249,7 @@ export class JSONPythonRenderer extends PythonRenderer { args.push(name); }); this.emitLine("return ", className, "(", arrayIntercalate(", ", args), ")"); - }, + } ); this.ensureBlankLine(); @@ -1245,7 +1263,7 @@ export class JSONPythonRenderer extends PythonRenderer { "result[", this.string(jsonName), "] = ", - makeValue(this.serializer(property, cp.type)), + makeValue(this.serializer(property, cp.type)) ); }); } else { @@ -1253,7 +1271,7 @@ export class JSONPythonRenderer extends PythonRenderer { "result[", this.string(jsonName), "] = ", - makeValue(this.serializer(property, cp.type)), + makeValue(this.serializer(property, cp.type)) ); } }); @@ -1261,7 +1279,7 @@ export class JSONPythonRenderer extends PythonRenderer { }); } - protected emitImports (): void { + protected emitImports(): void { super.emitImports(); if (this._haveDateutil) { this.emitLine("import dateutil.parser"); @@ -1279,32 +1297,32 @@ export class JSONPythonRenderer extends PythonRenderer { } } - protected emitSupportCode (): void { + protected emitSupportCode(): void { const map = Array.from(this._deserializerFunctions).map(f => [f, f] as [ConverterFunction, ConverterFunction]); this.forEachWithBlankLines(map, ["interposing", 2], cf => { this.emitConverter(cf); }); } - protected makeTopLevelDependencyNames (_t: Type, topLevelName: Name): DependencyName[] { + protected makeTopLevelDependencyNames(_t: Type, topLevelName: Name): DependencyName[] { const fromDict = new DependencyName( this._converterNamer, topLevelNameOrder, - l => `${l(topLevelName)}_from_dict`, + l => `${l(topLevelName)}_from_dict` ); const toDict = new DependencyName(this._converterNamer, topLevelNameOrder, l => `${l(topLevelName)}_to_dict`); this._topLevelConverterNames.set(topLevelName, { fromDict, toDict }); return [fromDict, toDict]; } - protected emitDefaultLeadingComments (): void { + protected emitDefaultLeadingComments(): void { this.ensureBlankLine(); if (this._haveDateutil) { this.emitCommentLines([ "This code parses date/times, so please", "", " pip install python-dateutil", - "", + "" ]); } @@ -1314,7 +1332,7 @@ export class JSONPythonRenderer extends PythonRenderer { " import json", "", "and then, to convert JSON from a string, do", - "", + "" ]); this.forEachTopLevel("none", (_, name) => { const { fromDict } = defined(this._topLevelConverterNames.get(name)); @@ -1322,7 +1340,7 @@ export class JSONPythonRenderer extends PythonRenderer { }); } - protected emitClosingCode (): void { + protected emitClosingCode(): void { this.forEachTopLevel(["interposing", 2], (t, name) => { const { fromDict, toDict } = defined(this._topLevelConverterNames.get(name)); const pythonType = this.pythonType(t); @@ -1330,14 +1348,14 @@ export class JSONPythonRenderer extends PythonRenderer { ["def ", fromDict, "(", this.typingDecl("s", "Any"), ")", this.typeHint(" -> ", pythonType), ":"], () => { this.emitLine("return ", makeValue(this.deserializer({ value: "s" }, t))); - }, + } ); this.ensureBlankLine(2); this.emitBlock( ["def ", toDict, "(x", this.typeHint(": ", pythonType), ")", this.typingReturn("Any"), ":"], () => { this.emitLine("return ", makeValue(this.serializer({ value: "x" }, t))); - }, + } ); }); } diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust.ts index fe5941cdc..9c69ed654 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust.ts @@ -121,7 +121,7 @@ export class RustTargetLanguage extends TargetLanguage { return new RustRenderer(this, renderContext, getOptionValues(rustOptions, untypedOptionValues)); } - constructor() { + public constructor() { super("Rust", ["rust", "rs", "rustlang"], "rs"); } @@ -267,7 +267,7 @@ const standardUnicodeRustEscape = (codePoint: number): string => { const rustStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeRustEscape)); export class RustRenderer extends ConvenienceRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, private readonly _options: OptionValues diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts index c173aed7c..843c2ad4d 100644 --- a/packages/quicktype-core/src/language/Scala3.ts +++ b/packages/quicktype-core/src/language/Scala3.ts @@ -193,7 +193,7 @@ const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s) const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); export class Scala3Renderer extends ConvenienceRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, protected readonly _scalaOptions: OptionValues @@ -250,10 +250,10 @@ export class Scala3Renderer extends ConvenienceRenderer { delimiter === "curly" ? ["{", "}"] : delimiter === "paren" - ? ["(", ")"] - : delimiter === "none" - ? ["", ""] - : ["{", "})"]; + ? ["(", ")"] + : delimiter === "none" + ? ["", ""] + : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); @@ -551,7 +551,7 @@ export class Smithy4sRenderer extends Scala3Renderer { } export class CirceRenderer extends Scala3Renderer { - seenUnionTypes: string[] = []; + private seenUnionTypes: string[] = []; protected circeEncoderForType(t: Type, _ = false, noOptional = false, paramName: string = ""): Sourcelike { return matchType( @@ -737,7 +737,7 @@ export class CirceRenderer extends Scala3Renderer { } export class Scala3TargetLanguage extends TargetLanguage { - constructor() { + public constructor() { super("Scala3", ["scala3"], "scala"); } @@ -745,11 +745,11 @@ export class Scala3TargetLanguage extends TargetLanguage { return [scala3Options.framework, scala3Options.packageName]; } - get supportsOptionalClassProperties(): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } diff --git a/packages/quicktype-core/src/language/Smithy4s.ts b/packages/quicktype-core/src/language/Smithy4s.ts index 816da3125..0b28a824e 100644 --- a/packages/quicktype-core/src/language/Smithy4s.ts +++ b/packages/quicktype-core/src/language/Smithy4s.ts @@ -153,7 +153,7 @@ const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s) const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); export class Smithy4sRenderer extends ConvenienceRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, protected readonly _scalaOptions: OptionValues @@ -210,10 +210,10 @@ export class Smithy4sRenderer extends ConvenienceRenderer { delimiter === "curly" ? ["{", "}"] : delimiter === "paren" - ? ["(", ")"] - : delimiter === "none" - ? ["", ""] - : ["{", "})"]; + ? ["(", ")"] + : delimiter === "none" + ? ["", ""] + : ["{", "})"]; this.emitLine(line, " ", open); this.indent(f); this.emitLine(close); @@ -521,7 +521,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { } export class SmithyTargetLanguage extends TargetLanguage { - constructor() { + public constructor() { super("Smithy", ["Smithy"], "smithy"); } @@ -529,11 +529,11 @@ export class SmithyTargetLanguage extends TargetLanguage { return [SmithyOptions.framework, SmithyOptions.packageName]; } - get supportsOptionalClassProperties(): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes(): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift.ts index bc8cd35ca..25cf19e02 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift.ts @@ -9,19 +9,15 @@ import { type TypeKind, type ClassProperty, type TransformedStringTypeKind, - type PrimitiveStringTypeKind, -} from "../Type"; -import { - EnumType, - ArrayType, - MapType, + type PrimitiveStringTypeKind } from "../Type"; +import { EnumType, ArrayType, MapType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike} from "../Source"; +import { type Sourcelike } from "../Source"; import { maybeAnnotated, modifySource } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; @@ -41,7 +37,7 @@ import { allLowerWordStyle, allUpperWordStyle, camelCase, - addPrefixIfNecessary, + addPrefixIfNecessary } from "../support/Strings"; import { type RenderContext, type ForEachPosition } from "../Renderer"; import { type StringTypeMapping } from "../TypeBuilder"; @@ -60,7 +56,7 @@ export const swiftOptions = { namedTypePrefix: new StringOption("type-prefix", "Prefix for type names", "PREFIX", "", "secondary"), useClasses: new EnumOption("struct-or-class", "Structs or classes", [ ["struct", false], - ["class", true], + ["class", true] ]), mutableProperties: new BooleanOption("mutable-properties", "Use var instead of let for object properties", false), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), @@ -69,16 +65,16 @@ export const swiftOptions = { "Code density", [ ["dense", true], - ["normal", false], + ["normal", false] ], "dense", - "secondary", + "secondary" ), linux: new BooleanOption("support-linux", "Support Linux", false, "secondary"), objcSupport: new BooleanOption( "objective-c-support", "Objects inherit from NSObject and @objcMembers is added to classes", - false, + false ), optionalEnums: new BooleanOption("optional-enums", "If no matching case is found enum value is set to null", false), swift5Support: new BooleanOption("swift-5-support", "Renders output in a Swift 5 compatible mode", false), @@ -86,17 +82,17 @@ export const swiftOptions = { multiFileOutput: new BooleanOption( "multi-file-output", "Renders each top-level object in its own Swift file", - false, + false ), accessLevel: new EnumOption( "access-level", "Access level", [ ["internal", "internal"], - ["public", "public"], + ["public", "public"] ], "internal", - "secondary", + "secondary" ), protocol: new EnumOption( "protocol", @@ -104,11 +100,11 @@ export const swiftOptions = { [ ["none", { equatable: false, hashable: false }], ["equatable", { equatable: true, hashable: false }], - ["hashable", { equatable: false, hashable: true }], + ["hashable", { equatable: false, hashable: true }] ], "none", - "secondary", - ), + "secondary" + ) }; // These are all recognized by Swift as ISO8601 date-times: @@ -125,7 +121,7 @@ export const swiftOptions = { const swiftDateTimeRegex = /^\d+-\d+-\d+T\d+:\d+:\d+([zZ]|[+-]\d+(:\d+)?)$/; class SwiftDateTimeRecognizer extends DefaultDateTimeRecognizer { - isDateTime (str: string): boolean { + public isDateTime(str: string): boolean { return swiftDateTimeRegex.exec(str) !== null; } } @@ -138,11 +134,11 @@ export interface SwiftProperty { } export class SwiftTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Swift", ["swift", "swift4"], "swift"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [ swiftOptions.justTypes, swiftOptions.useClasses, @@ -160,29 +156,29 @@ export class SwiftTargetLanguage extends TargetLanguage { swiftOptions.sendable, swiftOptions.swift5Support, swiftOptions.multiFileOutput, - swiftOptions.mutableProperties, + swiftOptions.mutableProperties ]; } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); mapping.set("date-time", "date-time"); return mapping; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - get supportsUnionsWithBothNumberTypes (): boolean { + public get supportsUnionsWithBothNumberTypes(): boolean { return true; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): SwiftRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): SwiftRenderer { return new SwiftRenderer(this, renderContext, getOptionValues(swiftOptions, untypedOptionValues)); } - get dateTimeRecognizer (): DateTimeRecognizer { + public get dateTimeRecognizer(): DateTimeRecognizer { return new SwiftDateTimeRecognizer(); } } @@ -286,24 +282,24 @@ const keywords = [ "convertDict", "convertDouble", "jsonString", - "jsonData", + "jsonData" ]; -function isPartCharacter (codePoint: number): boolean { +function isPartCharacter(codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); } -function isStartCharacter (codePoint: number): boolean { +function isStartCharacter(codePoint: number): boolean { return isPartCharacter(codePoint) && !isDigit(codePoint); } const legalizeName = legalizeCharacters(isPartCharacter); -function swiftNameStyle ( +function swiftNameStyle( prefix: string, isUpper: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle, + acronymsStyle: (s: string) => string = allUpperWordStyle ): string { const words = splitIntoWords(original); const combined = combineWords( @@ -314,12 +310,12 @@ function swiftNameStyle ( isUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, "", - isStartCharacter, + isStartCharacter ); return addPrefixIfNecessary(prefix, combined); } -function unicodeEscape (codePoint: number): string { +function unicodeEscape(codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; } @@ -332,15 +328,15 @@ export class SwiftRenderer extends ConvenienceRenderer { private _needNull = false; - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { if (this._options.alamofire) { return ["DataRequest", ...keywords]; } @@ -348,73 +344,73 @@ export class SwiftRenderer extends ConvenienceRenderer { return keywords; } - protected forbiddenForObjectProperties (_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { return { names: ["fromURL", "json"], includeGlobalForbidden: true }; } - protected forbiddenForEnumCases (_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected forbiddenForUnionMembers (_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("upper", s => - swiftNameStyle(this._options.namedTypePrefix, true, s, acronymStyle(this._options.acronymStyle)), + swiftNameStyle(this._options.namedTypePrefix, true, s, acronymStyle(this._options.acronymStyle)) ); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return this.lowerNamingFunction; } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return this.lowerNamingFunction; } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return this.lowerNamingFunction; } - protected isImplicitCycleBreaker (t: Type): boolean { + protected isImplicitCycleBreaker(t: Type): boolean { const kind = t.kind; return kind === "array" || kind === "map"; } - protected emitDescriptionBlock (lines: Sourcelike[]): void { + protected emitDescriptionBlock(lines: Sourcelike[]): void { this.emitCommentLines(lines, { lineStart: "/// " }); } - private emitBlock (line: Sourcelike, f: () => void): void { + private emitBlock(line: Sourcelike, f: () => void): void { this.emitLine(line, " {"); this.indent(f); this.emitLine("}"); } - private emitBlockWithAccess (line: Sourcelike, f: () => void): void { + private emitBlockWithAccess(line: Sourcelike, f: () => void): void { this.emitBlock([this.accessLevel, line], f); } - private justTypesCase (justTypes: Sourcelike, notJustTypes: Sourcelike): Sourcelike { + private justTypesCase(justTypes: Sourcelike, notJustTypes: Sourcelike): Sourcelike { if (this._options.justTypes) return justTypes; else return notJustTypes; } - private get lowerNamingFunction () { + private get lowerNamingFunction() { return funPrefixNamer("lower", s => swiftNameStyle("", false, s, acronymStyle(this._options.acronymStyle))); } - protected swiftPropertyType (p: ClassProperty): Sourcelike { - if (p.isOptional || this._options.optionalEnums && p.type.kind === "enum") { + protected swiftPropertyType(p: ClassProperty): Sourcelike { + if (p.isOptional || (this._options.optionalEnums && p.type.kind === "enum")) { return [this.swiftType(p.type, true, true), "?"]; } else { return this.swiftType(p.type, true); } } - protected swiftType (t: Type, withIssues = false, noOptional = false): Sourcelike { + protected swiftType(t: Type, withIssues = false, noOptional = false): Sourcelike { const optional = noOptional ? "" : "?"; return matchType( t, @@ -423,7 +419,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return maybeAnnotated( withIssues, anyTypeIssueAnnotation, - this.justTypesCase(["Any", optional], "JSONAny"), + this.justTypesCase(["Any", optional], "JSONAny") ); }, _nullType => { @@ -431,7 +427,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return maybeAnnotated( withIssues, nullTypeIssueAnnotation, - this.justTypesCase("NSNull", ["JSONNull", optional]), + this.justTypesCase("NSNull", ["JSONNull", optional]) ); }, _boolType => "Bool", @@ -453,11 +449,11 @@ export class SwiftRenderer extends ConvenienceRenderer { } else { return panic(`Transformed string type ${transformedStringType.kind} not supported`); } - }, + } ); } - protected proposedUnionMemberNameForTypeKind (kind: TypeKind): string | null { + protected proposedUnionMemberNameForTypeKind(kind: TypeKind): string | null { if (kind === "enum") { return "enumeration"; } @@ -469,7 +465,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return null; } - private renderSingleFileHeaderComments (): void { + private renderSingleFileHeaderComments(): void { this.emitLineOnce("// This file was generated from JSON Schema using quicktype, do not modify it directly."); this.emitLineOnce("// To parse the JSON, add this file to your project and do:"); this.emitLineOnce("//"); @@ -480,7 +476,7 @@ export class SwiftRenderer extends ConvenienceRenderer { modifySource(camelCase, topLevelName), " = try ", topLevelName, - "(json)", + "(json)" ); } else { this.emitLineOnce( @@ -489,19 +485,19 @@ export class SwiftRenderer extends ConvenienceRenderer { " = ", "try? JSONDecoder().decode(", topLevelName, - ".self, from: jsonData)", + ".self, from: jsonData)" ); } }); } - private renderHeader (type: Type, name: Name): void { + private renderHeader(type: Type, name: Name): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else if (!this._options.justTypes) { if (this._options.multiFileOutput) { this.emitLineOnce( - "// This file was generated from JSON Schema using quicktype, do not modify it directly.", + "// This file was generated from JSON Schema using quicktype, do not modify it directly." ); this.emitLineOnce("// To parse the JSON, add this file to your project and do:"); this.emitLineOnce("//"); @@ -514,7 +510,7 @@ export class SwiftRenderer extends ConvenienceRenderer { " = ", "try? newJSONDecoder().decode(", name, - ".self, from: jsonData)", + ".self, from: jsonData)" ); } } @@ -534,10 +530,10 @@ export class SwiftRenderer extends ConvenienceRenderer { this.emitLine("//"); this.emitLine("// Hashable or Equatable:"); this.emitLine( - "// The compiler will not be able to synthesize the implementation of Hashable or Equatable", + "// The compiler will not be able to synthesize the implementation of Hashable or Equatable" ); this.emitLine( - "// for types that require the use of JSONAny, nor will the implementation of Hashable be", + "// for types that require the use of JSONAny, nor will the implementation of Hashable be" ); this.emitLine("// synthesized for types that have collections (such as arrays or dictionaries)."); } @@ -556,11 +552,11 @@ export class SwiftRenderer extends ConvenienceRenderer { this.ensureBlankLine(); } - private renderTopLevelAlias (t: Type, name: Name): void { + private renderTopLevelAlias(t: Type, name: Name): void { this.emitLine(this.accessLevel, "typealias ", name, " = ", this.swiftType(t, true)); } - protected getProtocolsArray (kind: "struct" | "class" | "enum"): string[] { + protected getProtocolsArray(kind: "struct" | "class" | "enum"): string[] { const protocols: string[] = []; // [Michael Fey (@MrRooni), 2019-4-24] Technically NSObject isn't a "protocol" in this instance, but this felt like the best place to slot in this superclass declaration. @@ -589,9 +585,9 @@ export class SwiftRenderer extends ConvenienceRenderer { return protocols; } - private getProtocolString ( + private getProtocolString( kind: "struct" | "class" | "enum", - baseClass: string | undefined = undefined, + baseClass: string | undefined = undefined ): Sourcelike { let protocols = this.getProtocolsArray(kind); if (baseClass) { @@ -601,8 +597,8 @@ export class SwiftRenderer extends ConvenienceRenderer { return protocols.length > 0 ? ": " + protocols.join(", ") : ""; } - private getEnumPropertyGroups (c: ClassType) { - type PropertyGroup = Array<{ label?: string, name: Name, }>; + private getEnumPropertyGroups(c: ClassType) { + type PropertyGroup = Array<{ label?: string; name: Name }>; let groups: PropertyGroup[] = []; let group: PropertyGroup = []; @@ -631,13 +627,13 @@ export class SwiftRenderer extends ConvenienceRenderer { } /// Access level with trailing space (e.g. "public "), or empty string - private get accessLevel (): string { + private get accessLevel(): string { return this._options.accessLevel === "internal" ? "" // internal is default, so we don't have to emit it : this._options.accessLevel + " "; } - private get objcMembersDeclaration (): string { + private get objcMembersDeclaration(): string { if (this._options.objcSupport) { return "@objcMembers "; } @@ -646,7 +642,7 @@ export class SwiftRenderer extends ConvenienceRenderer { } /// startFile takes a file name, appends ".swift" to it and sets it as the current filename. - protected startFile (basename: Sourcelike): void { + protected startFile(basename: Sourcelike): void { if (this._options.multiFileOutput === false) { return; } @@ -658,7 +654,7 @@ export class SwiftRenderer extends ConvenienceRenderer { } /// endFile pushes the current file name onto the collection of finished files and then resets the current file name. These finished files are used in index.ts to write the output. - protected endFile (): void { + protected endFile(): void { if (this._options.multiFileOutput === false) { return; } @@ -667,18 +663,18 @@ export class SwiftRenderer extends ConvenienceRenderer { this._currentFilename = undefined; } - protected propertyLinesDefinition (name: Name, parameter: ClassProperty): Sourcelike { + protected propertyLinesDefinition(name: Name, parameter: ClassProperty): Sourcelike { const useMutableProperties = this._options.mutableProperties; return [ this.accessLevel, useMutableProperties ? "var " : "let ", name, ": ", - this.swiftPropertyType(parameter), + this.swiftPropertyType(parameter) ]; } - private renderClassDefinition (c: ClassType, className: Name): void { + private renderClassDefinition(c: ClassType, className: Name): void { this.startFile(className); this.renderHeader(c, className); @@ -710,10 +706,10 @@ export class SwiftRenderer extends ConvenienceRenderer { ? "@OptionallyDecodable " : "", this.accessLevel, - useMutableProperties || this._options.optionalEnums && lastProperty.type.kind === "enum" + useMutableProperties || (this._options.optionalEnums && lastProperty.type.kind === "enum") ? "var " - : "let ", - ], + : "let " + ] ]; lastNames.forEach((n, i) => { if (i > 0) sources.push(", "); @@ -768,11 +764,11 @@ export class SwiftRenderer extends ConvenienceRenderer { for (const group of groups) { const { name, label } = group[0]; if (this._options.explicitCodingKeys && label !== undefined) { - this.emitLine("case ", name, " = \"", label, "\""); + this.emitLine("case ", name, ' = "', label, '"'); } else { const names = arrayIntercalate( ", ", - group.map(p => p.name), + group.map(p => p.name) ); this.emitLine("case ", names); } @@ -826,7 +822,7 @@ export class SwiftRenderer extends ConvenienceRenderer { this.endFile(); } - protected initializableProperties (c: ClassType): SwiftProperty[] { + protected initializableProperties(c: ClassType): SwiftProperty[] { const properties: SwiftProperty[] = []; this.forEachClassProperty(c, "none", (name, jsonName, parameter, position) => { const property = { name, jsonName, parameter, position }; @@ -835,7 +831,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return properties; } - private emitNewEncoderDecoder (): void { + private emitNewEncoderDecoder(): void { this.emitBlock("func newJSONDecoder() -> JSONDecoder", () => { this.emitLine("let decoder = JSONDecoder()"); if (!this._options.linux) { @@ -885,7 +881,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } - private emitConvenienceInitializersExtension (c: ClassType, className: Name): void { + private emitConvenienceInitializersExtension(c: ClassType, className: Name): void { const isClass = this._options.useClasses || this.isCycleBreakerType(c); const convenience = isClass ? "convenience " : ""; @@ -916,10 +912,10 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); [convenience, "init(_ json: String, using encoding: String.Encoding = .utf8) throws"], () => { this.emitBlock("guard let data = json.data(using: encoding) else", () => { - this.emitLine("throw NSError(domain: \"JSONDecoding\", code: 0, userInfo: nil)"); + this.emitLine('throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)'); }); this.emitLine("try self.init(data: data)"); - }, + } ); this.ensureBlankLine(); this.emitBlock([convenience, "init(fromURL url: URL) throws"], () => { @@ -941,7 +937,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } - private renderEnumDefinition (e: EnumType, enumName: Name): void { + private renderEnumDefinition(e: EnumType, enumName: Name): void { this.startFile(enumName); this.emitLineOnce("import Foundation"); @@ -959,7 +955,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } else { this.emitBlockWithAccess(["enum ", enumName, protocolString], () => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("case ", name, " = \"", stringEscape(jsonName), "\""); + this.emitLine("case ", name, ' = "', stringEscape(jsonName), '"'); }); }); } @@ -967,13 +963,13 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.endFile(); } - private renderUnionDefinition (u: UnionType, unionName: Name): void { + private renderUnionDefinition(u: UnionType, unionName: Name): void { this.startFile(unionName); this.emitLineOnce("import Foundation"); this.ensureBlankLine(); - function sortBy (t: Type): string { + function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; return "_" + kind; @@ -1040,7 +1036,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.endFile(); } - private emitTopLevelMapAndArrayConvenienceInitializerExtensions (t: Type, name: Name): void { + private emitTopLevelMapAndArrayConvenienceInitializerExtensions(t: Type, name: Name): void { let extensionSource: Sourcelike; if (t instanceof ArrayType) { @@ -1058,7 +1054,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.ensureBlankLine(); this.emitBlock("init(_ json: String, using encoding: String.Encoding = .utf8) throws", () => { this.emitBlock("guard let data = json.data(using: encoding) else", () => { - this.emitLine("throw NSError(domain: \"JSONDecoding\", code: 0, userInfo: nil)"); + this.emitLine('throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)'); }); this.emitLine("try self.init(data: data)"); }); @@ -1077,13 +1073,13 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } - private emitDecodingError (name: Name): void { + private emitDecodingError(name: Name): void { this.emitLine( "throw DecodingError.typeMismatch(", name, - ".self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Wrong type for ", + '.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ', name, - "\"))", + '"))' ); } @@ -1095,17 +1091,17 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.forEachTopLevel( "leading", (t: Type, name: Name) => this.renderTopLevelAlias(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); if (this._options.convenienceInitializers) { this.ensureBlankLine(); this.forEachTopLevel("leading-and-interposing", (t: Type, name: Name) => - this.emitTopLevelMapAndArrayConvenienceInitializerExtensions(t, name), + this.emitTopLevelMapAndArrayConvenienceInitializerExtensions(t, name) ); } - if (!this._options.justTypes && this._options.convenienceInitializers || this._options.alamofire) { + if ((!this._options.justTypes && this._options.convenienceInitializers) || this._options.alamofire) { this.ensureBlankLine(); this.emitMark("Helper functions for creating encoders and decoders", true); this.ensureBlankLine(); @@ -1400,7 +1396,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.endFile(); }; - private emitConvenienceMutator (c: ClassType, className: Name) { + private emitConvenienceMutator(c: ClassType, className: Name) { this.emitLine("func with("); this.indent(() => { this.forEachClassProperty(c, "none", (name, _, p, position) => { @@ -1409,7 +1405,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); ": ", this.swiftPropertyType(p), "? = nil", - position !== "only" && position !== "last" ? "," : "", + position !== "only" && position !== "last" ? "," : "" ); }); }); @@ -1423,7 +1419,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); name, " ?? self.", name, - position !== "only" && position !== "last" ? "," : "", + position !== "only" && position !== "last" ? "," : "" ); }); }); @@ -1431,11 +1427,11 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } - protected emitMark (line: Sourcelike, horizontalLine = false) { + protected emitMark(line: Sourcelike, horizontalLine = false) { this.emitLine("// MARK:", horizontalLine ? " - " : " ", line); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { if (this._options.multiFileOutput === false) { this.renderSingleFileHeaderComments(); } @@ -1444,7 +1440,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); "leading-and-interposing", (c: ClassType, className: Name) => this.renderClassDefinition(c, className), (e: EnumType, enumName: Name) => this.renderEnumDefinition(e, enumName), - (u: UnionType, unionName: Name) => this.renderUnionDefinition(u, unionName), + (u: UnionType, unionName: Name) => this.renderUnionDefinition(u, unionName) ); if (!this._options.justTypes) { @@ -1452,7 +1448,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } } - private emitAlamofireExtension () { + private emitAlamofireExtension() { this.ensureBlankLine(); this.emitBlockWithAccess("extension DataRequest", () => { this @@ -1481,11 +1477,11 @@ fileprivate func responseDecodable(queue: DispatchQueue? = nil, co name, "(queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse<", name, - ">) -> Void) -> Self", + ">) -> Void) -> Self" ], () => { this.emitLine("return responseDecodable(queue: queue, completionHandler: completionHandler)"); - }, + } ); }); }); diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts index 2629cff39..772260388 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts @@ -16,7 +16,7 @@ import { isLetterOrUnderscore, splitIntoWords, stringEscape, - utf16StringEscape, + utf16StringEscape } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; import { legalizeName } from "./JavaScript"; @@ -25,48 +25,50 @@ import { panic } from "../support/Support"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; export const typeScriptEffectSchemaOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false), + justSchema: new BooleanOption("just-schema", "Schema only", false) }; export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage { - protected getOptions (): Array> { + protected getOptions(): Array> { return []; } - constructor ( + public constructor( displayName: string = "TypeScript Effect Schema", names: string[] = ["typescript-effect-schema"], - extension: string = "ts", + extension: string = "ts" ) { super(displayName, names, extension); } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): TypeScriptEffectSchemaRenderer { return new TypeScriptEffectSchemaRenderer( this, renderContext, - getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues), + getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues) ); } } export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { - constructor ( + private emittedObjects = new Set(); + + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; } - protected nameStyle (original: string, upper: boolean): string { + protected nameStyle(original: string, upper: boolean): string { const acronyms = acronymStyle(AcronymStyleOptions.Camel); const words = splitIntoWords(original); return combineWords( @@ -77,43 +79,41 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isLetterOrUnderscore, + isLetterOrUnderscore ); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); } - private importStatement (lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { + private importStatement(lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { return ["import ", lhs, " from ", moduleName, ";"]; } - protected emitImports (): void { + protected emitImports(): void { this.ensureBlankLine(); - this.emitLine(this.importStatement("* as S", "\"@effect/schema/Schema\"")); + this.emitLine(this.importStatement("* as S", '"@effect/schema/Schema"')); } - typeMapTypeForProperty (p: ClassProperty): Sourcelike { + private typeMapTypeForProperty(p: ClassProperty): Sourcelike { const typeMap = this.typeMapTypeFor(p.type); return p.isOptional ? ["S.optional(", typeMap, ")"] : typeMap; } - emittedObjects = new Set(); - - typeMapTypeFor (t: Type, required: boolean = true): Sourcelike { + private typeMapTypeFor(t: Type, required: boolean = true): Sourcelike { if (t.kind === "class" || t.kind === "object" || t.kind === "enum") { const name = this.nameForNamedType(t); if (this.emittedObjects.has(name)) { @@ -137,13 +137,13 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { _enumType => panic("Should already be handled."), unionType => { const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false), + this.typeMapTypeFor(type, false) ); return ["S.union(", ...arrayIntercalate(", ", children), ")"]; }, _transformedStringType => { return "S.string"; - }, + } ); if (required) { @@ -153,10 +153,10 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { return match; } - private emitObject (name: Name, t: ObjectType) { + private emitObject(name: Name, t: ObjectType) { this.emittedObjects.add(name); this.ensureBlankLine(); - this.emitLine("\nexport class ", name, " extends S.Class<", name, ">(\"", name, "\")({"); + this.emitLine("\nexport class ", name, " extends S.Class<", name, '>("', name, '")({'); this.indent(() => { this.forEachClassProperty(t, "none", (_, jsonName, property) => { this.emitLine(`"${utf16StringEscape(jsonName)}"`, ": ", this.typeMapTypeForProperty(property), ","); @@ -165,15 +165,15 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { this.emitLine("}) {}"); } - private emitEnum (e: EnumType, enumName: Name): void { + private emitEnum(e: EnumType, enumName: Name): void { this.emittedObjects.add(enumName); this.ensureBlankLine(); this.emitDescription(this.descriptionForType(e)); this.emitLine("\nexport const ", enumName, " = ", "S.literal("); this.indent(() => this.forEachEnumCase(e, "none", (_, jsonName) => { - this.emitLine("\"", stringEscape(jsonName), "\","); - }), + this.emitLine('"', stringEscape(jsonName), '",'); + }) ); this.emitLine(");"); if (!this._options.justSchema) { @@ -181,7 +181,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { } } - protected walkObjectNames (type: ObjectType) { + protected walkObjectNames(type: ObjectType) { const names: Name[] = []; const recurse = (type: Type) => { @@ -208,7 +208,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { return names; } - protected emitSchemas (): void { + protected emitSchemas(): void { this.ensureBlankLine(); this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => { @@ -253,7 +253,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { order.forEach(i => this.emitGatheredSource(this.gatherSource(() => this.emitObject(mapKey[i], mapValue[i])))); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } diff --git a/packages/quicktype-core/src/language/TypeScriptFlow.ts b/packages/quicktype-core/src/language/TypeScriptFlow.ts index f3dcb0765..e7a12f58c 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow.ts @@ -1,22 +1,16 @@ -import { type Type, type ClassType} from "../Type"; +import { type Type, type ClassType } from "../Type"; import { ArrayType, UnionType, EnumType } from "../Type"; import { matchType, nullableFromUnion, isNamedType } from "../TypeUtils"; import { utf16StringEscape, camelCase } from "../support/Strings"; -import { type Sourcelike, type MultiWord} from "../Source"; +import { type Sourcelike, type MultiWord } from "../Source"; import { modifySource, singleWord, parenIfNeeded, multiWord } from "../Source"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { BooleanOption, getOptionValues } from "../RendererOptions"; -import { - type JavaScriptTypeAnnotations} from "./JavaScript"; -import { - javaScriptOptions, - JavaScriptTargetLanguage, - JavaScriptRenderer, - legalizeName, -} from "./JavaScript"; +import { type JavaScriptTypeAnnotations } from "./JavaScript"; +import { javaScriptOptions, JavaScriptTargetLanguage, JavaScriptRenderer, legalizeName } from "./JavaScript"; import { defined, panic } from "../support/Support"; import { type TargetLanguage } from "../TargetLanguage"; import { type RenderContext } from "../Renderer"; @@ -31,9 +25,9 @@ export const tsFlowOptions = Object.assign({}, javaScriptOptions, { preferConstValues: new BooleanOption( "prefer-const-values", "Use string instead of enum for string enums with single value", - false, + false ), - readonly: new BooleanOption("readonly", "Use readonly type members", false), + readonly: new BooleanOption("readonly", "Use readonly type members", false) }); const tsFlowTypeAnnotations = { @@ -42,11 +36,11 @@ const tsFlowTypeAnnotations = { anyMap: ": { [k: string]: any }", string: ": string", stringArray: ": string[]", - boolean: ": boolean", + boolean: ": boolean" }; export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetLanguage { - protected getOptions (): Array> { + protected getOptions(): Array> { return [ tsFlowOptions.justTypes, tsFlowOptions.nicePropertyNames, @@ -59,34 +53,34 @@ export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetL tsFlowOptions.preferUnions, tsFlowOptions.preferTypes, tsFlowOptions.preferConstValues, - tsFlowOptions.readonly, + tsFlowOptions.readonly ]; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - protected abstract makeRenderer ( + protected abstract makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, } + untypedOptionValues: { [name: string]: any } ): JavaScriptRenderer; } export class TypeScriptTargetLanguage extends TypeScriptFlowBaseTargetLanguage { - constructor () { + public constructor() { super("TypeScript", ["typescript", "ts", "tsx"], "ts"); } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): TypeScriptRenderer { return new TypeScriptRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); } } -function quotePropertyName (original: string): string { +function quotePropertyName(original: string): string { const escaped = utf16StringEscape(original); const quoted = `"${escaped}"`; @@ -104,15 +98,15 @@ function quotePropertyName (original: string): string { } export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _tsFlowOptions: OptionValues, + protected readonly _tsFlowOptions: OptionValues ) { super(targetLanguage, renderContext, _tsFlowOptions); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { if (this._tsFlowOptions.nicePropertyNames) { return funPrefixNamer("properties", s => this.nameStyle(s, false)); } else { @@ -120,7 +114,7 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } } - protected sourceFor (t: Type): MultiWord { + protected sourceFor(t: Type): MultiWord { if (this._tsFlowOptions.preferConstValues && t.kind === "enum" && t instanceof EnumType && t.cases.size === 1) { const item = t.cases.values().next().value; return singleWord(`"${utf16StringEscape(item)}"`); @@ -141,7 +135,7 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { arrayType => { const itemType = this.sourceFor(arrayType.items); if ( - arrayType.items instanceof UnionType && !this._tsFlowOptions.declareUnions || + (arrayType.items instanceof UnionType && !this._tsFlowOptions.declareUnions) || arrayType.items instanceof ArrayType ) { return singleWord(["Array<", itemType.source, ">"]); @@ -166,15 +160,15 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } return singleWord("string"); - }, + } ); } - protected abstract emitEnum (e: EnumType, enumName: Name): void; + protected abstract emitEnum(e: EnumType, enumName: Name): void; - protected abstract emitClassBlock (c: ClassType, className: Name): void; + protected abstract emitClassBlock(c: ClassType, className: Name): void; - protected emitClassBlockBody (c: ClassType): void { + protected emitClassBlockBody(c: ClassType): void { this.emitPropertyTable(c, (name, _jsonName, p) => { const t = p.type; @@ -187,7 +181,7 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { return [ [propertyName, p.isOptional ? "?" : "", ": "], - [this.sourceFor(t).source, ";"], + [this.sourceFor(t).source, ";"] ]; }); @@ -197,12 +191,12 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } } - private emitClass (c: ClassType, className: Name) { + private emitClass(c: ClassType, className: Name) { this.emitDescription(this.descriptionForType(c)); this.emitClassBlock(c, className); } - emitUnion (u: UnionType, unionName: Name) { + protected emitUnion(u: UnionType, unionName: Name) { if (!this._tsFlowOptions.declareUnions) { return; } @@ -213,54 +207,54 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { this.emitLine("export type ", unionName, " = ", children.source, ";"); } - protected emitTypes (): void { + protected emitTypes(): void { this.forEachNamedType( "leading-and-interposing", (c: ClassType, n: Name) => this.emitClass(c, n), (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n), + (u, n) => this.emitUnion(u, n) ); } - protected emitUsageComments (): void { + protected emitUsageComments(): void { if (this._tsFlowOptions.justTypes) return; super.emitUsageComments(); } - protected deserializerFunctionLine (t: Type, name: Name): Sourcelike { + protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["function to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; } - protected serializerFunctionLine (t: Type, name: Name): Sourcelike { + protected serializerFunctionLine(t: Type, name: Name): Sourcelike { const camelCaseName = modifySource(camelCase, name); const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["function ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; } - protected get moduleLine (): string | undefined { + protected get moduleLine(): string | undefined { return undefined; } - protected get castFunctionLines (): [string, string] { + protected get castFunctionLines(): [string, string] { return ["function cast(val: any, typ: any): T", "function uncast(val: T, typ: any): any"]; } - protected get typeAnnotations (): JavaScriptTypeAnnotations { + protected get typeAnnotations(): JavaScriptTypeAnnotations { throw new Error("not implemented"); } - protected emitConvertModule (): void { + protected emitConvertModule(): void { if (this._tsFlowOptions.justTypes) return; super.emitConvertModule(); } - protected emitConvertModuleHelpers (): void { + protected emitConvertModuleHelpers(): void { if (this._tsFlowOptions.justTypes) return; super.emitConvertModuleHelpers(); } - protected emitModuleExports (): void { + protected emitModuleExports(): void { if (this._tsFlowOptions.justTypes) { return; } else { @@ -270,46 +264,46 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return ["Array", "Date"]; } - protected deserializerFunctionLine (t: Type, name: Name): Sourcelike { + protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["public static to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; } - protected serializerFunctionLine (t: Type, name: Name): Sourcelike { + protected serializerFunctionLine(t: Type, name: Name): Sourcelike { const camelCaseName = modifySource(camelCase, name); const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; return ["public static ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; } - protected get moduleLine (): string | undefined { + protected get moduleLine(): string | undefined { return "export class Convert"; } - protected get typeAnnotations (): JavaScriptTypeAnnotations { + protected get typeAnnotations(): JavaScriptTypeAnnotations { return Object.assign({ never: ": never" }, tsFlowTypeAnnotations); } - protected emitModuleExports (): void { + protected emitModuleExports(): void { return; } - protected emitUsageImportComment (): void { + protected emitUsageImportComment(): void { const topLevelNames: Sourcelike[] = []; this.forEachTopLevel( "none", (_t, name) => { topLevelNames.push(", ", name); }, - isNamedType, + isNamedType ); - this.emitLine("// import { Convert", topLevelNames, " } from \"./file\";"); + this.emitLine("// import { Convert", topLevelNames, ' } from "./file";'); } - protected emitEnum (e: EnumType, enumName: Name): void { + protected emitEnum(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); // enums with only one value are emitted as constants @@ -335,7 +329,7 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { } } - protected emitClassBlock (c: ClassType, className: Name): void { + protected emitClassBlock(c: ClassType, className: Name): void { this.emitBlock( this._tsFlowOptions.preferTypes ? ["export type ", className, " = "] @@ -343,36 +337,36 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { "", () => { this.emitClassBlockBody(c); - }, + } ); } } export class FlowTargetLanguage extends TypeScriptFlowBaseTargetLanguage { - constructor () { + public constructor() { super("Flow", ["flow"], "js"); } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): FlowRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): FlowRenderer { return new FlowRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); } } export class FlowRenderer extends TypeScriptFlowBaseRenderer { - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; } - protected get typeAnnotations (): JavaScriptTypeAnnotations { + protected get typeAnnotations(): JavaScriptTypeAnnotations { return Object.assign({ never: "" }, tsFlowTypeAnnotations); } - protected emitEnum (e: EnumType, enumName: Name): void { + protected emitEnum(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); const lines: string[][] = []; this.forEachEnumCase(e, "none", (_, jsonName) => { const maybeOr = lines.length === 0 ? " " : "| "; - lines.push([maybeOr, "\"", utf16StringEscape(jsonName), "\""]); + lines.push([maybeOr, '"', utf16StringEscape(jsonName), '"']); }); defined(lines[lines.length - 1]).push(";"); @@ -384,13 +378,13 @@ export class FlowRenderer extends TypeScriptFlowBaseRenderer { }); } - protected emitClassBlock (c: ClassType, className: Name): void { + protected emitClassBlock(c: ClassType, className: Name): void { this.emitBlock(["export type ", className, " = "], ";", () => { this.emitClassBlockBody(c); }); } - protected emitSourceStructure () { + protected emitSourceStructure() { this.emitLine("// @flow"); this.ensureBlankLine(); super.emitSourceStructure(); diff --git a/packages/quicktype-core/src/language/TypeScriptZod.ts b/packages/quicktype-core/src/language/TypeScriptZod.ts index 75b9e7f96..abc84f71e 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod.ts @@ -1,10 +1,10 @@ import { type StringTypeMapping } from "TypeBuilder"; import { arrayIntercalate } from "collection-utils"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer} from "../Naming"; +import { type Name, type Namer } from "../Naming"; import { funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues} from "../RendererOptions"; +import { type Option, type OptionValues } from "../RendererOptions"; import { BooleanOption, getOptionValues } from "../RendererOptions"; import { type Sourcelike } from "../Source"; import { TargetLanguage } from "../TargetLanguage"; @@ -13,14 +13,9 @@ import { type EnumType, type PrimitiveStringTypeKind, type TransformedStringTypeKind, - type Type, -} from "../Type"; -import { - ArrayType, - ClassType, - ObjectType, - SetOperationType, + type Type } from "../Type"; +import { ArrayType, ClassType, ObjectType, SetOperationType } from "../Type"; import { matchType } from "../TypeUtils"; import { AcronymStyleOptions, acronymStyle } from "../support/Acronyms"; import { @@ -31,65 +26,65 @@ import { isLetterOrUnderscore, splitIntoWords, stringEscape, - utf16StringEscape, + utf16StringEscape } from "../support/Strings"; import { panic } from "../support/Support"; import { legalizeName } from "./JavaScript"; export const typeScriptZodOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false), + justSchema: new BooleanOption("just-schema", "Schema only", false) }; export class TypeScriptZodTargetLanguage extends TargetLanguage { - protected getOptions (): Array> { + protected getOptions(): Array> { return []; } - constructor ( + public constructor( displayName: string = "TypeScript Zod", names: string[] = ["typescript-zod"], - extension: string = "ts", + extension: string = "ts" ) { super(displayName, names, extension); } - get stringTypeMapping (): StringTypeMapping { + public get stringTypeMapping(): StringTypeMapping { const mapping: Map = new Map(); const dateTimeType = "date-time"; mapping.set("date-time", dateTimeType); return mapping; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - protected makeRenderer ( + protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any, }, + untypedOptionValues: { [name: string]: any } ): TypeScriptZodRenderer { return new TypeScriptZodRenderer( this, renderContext, - getOptionValues(typeScriptZodOptions, untypedOptionValues), + getOptionValues(typeScriptZodOptions, untypedOptionValues) ); } } export class TypeScriptZodRenderer extends ConvenienceRenderer { - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues, + protected readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; } - protected nameStyle (original: string, upper: boolean): string { + protected nameStyle(original: string, upper: boolean): string { const acronyms = acronymStyle(AcronymStyleOptions.Camel); const words = splitIntoWords(original); return combineWords( @@ -100,41 +95,41 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isLetterOrUnderscore, + isLetterOrUnderscore ); } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return funPrefixNamer("types", s => this.nameStyle(s, true)); } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return funPrefixNamer("properties", s => this.nameStyle(s, true)); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); } - protected importStatement (lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { + protected importStatement(lhs: Sourcelike, moduleName: Sourcelike): Sourcelike { return ["import ", lhs, " from ", moduleName, ";"]; } - protected emitImports (): void { + protected emitImports(): void { this.ensureBlankLine(); - this.emitLine(this.importStatement("* as z", "\"zod\"")); + this.emitLine(this.importStatement("* as z", '"zod"')); } - protected typeMapTypeForProperty (p: ClassProperty): Sourcelike { + protected typeMapTypeForProperty(p: ClassProperty): Sourcelike { const typeMap = this.typeMapTypeFor(p.type); return p.isOptional ? [typeMap, ".optional()"] : typeMap; } - protected typeMapTypeFor (t: Type, required: boolean = true): Sourcelike { + protected typeMapTypeFor(t: Type, required: boolean = true): Sourcelike { if (["class", "object", "enum"].includes(t.kind)) { return [this.nameForNamedType(t), "Schema"]; } @@ -153,7 +148,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { _enumType => panic("Should already be handled."), unionType => { const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false), + this.typeMapTypeFor(type, false) ); return ["z.union([", ...arrayIntercalate(", ", children), "])"]; }, @@ -163,7 +158,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { } return "z.string()"; - }, + } ); if (required) { @@ -173,7 +168,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { return match; } - protected emitObject (name: Name, t: ObjectType) { + protected emitObject(name: Name, t: ObjectType) { this.ensureBlankLine(); this.emitLine("\nexport const ", name, "Schema = ", "z.object({"); this.indent(() => { @@ -187,14 +182,14 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { } } - protected emitEnum (e: EnumType, enumName: Name): void { + protected emitEnum(e: EnumType, enumName: Name): void { this.ensureBlankLine(); this.emitDescription(this.descriptionForType(e)); this.emitLine("\nexport const ", enumName, "Schema = ", "z.enum(["); this.indent(() => this.forEachEnumCase(e, "none", (_, jsonName) => { - this.emitLine("\"", stringEscape(jsonName), "\","); - }), + this.emitLine('"', stringEscape(jsonName), '",'); + }) ); this.emitLine("]);"); if (!this._options.justSchema) { @@ -209,7 +204,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { * Primitive types don't need defining and enums are output before other types, hence, * these are ignored. */ - static extractUnderlyingTyperefs (type: Type): number[] { + private static extractUnderlyingTyperefs(type: Type): number[] { let typeRefs: number[] = []; // Ignore enums and primitives if (!type.isPrimitive() && type.kind != "enum") { @@ -249,7 +244,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { return typeRefs; } - protected emitSchemas (): void { + protected emitSchemas(): void { this.ensureBlankLine(); this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => { @@ -315,7 +310,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { foundAllChildren = foundAllChildren && found; } else { console.error( - "A child type reference was not found amongst all Object definitions! TypeRef: " + childRef, + "A child type reference was not found amongst all Object definitions! TypeRef: " + childRef ); } }); @@ -335,7 +330,9 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { if (passNum > MAX_PASSES) { // giving up order.push(...deferredIndices); - console.warn("Exceeded maximum number of passes when determining output order, output may contain forward references"); + console.warn( + "Exceeded maximum number of passes when determining output order, output may contain forward references" + ); } } while (indices.length > 0 && passNum <= MAX_PASSES); @@ -343,7 +340,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { order.forEach(i => this.emitGatheredSource(this.gatherSource(() => this.emitObject(mapName[i], mapType[i])))); } - protected emitSourceStructure (): void { + protected emitSourceStructure(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } diff --git a/packages/quicktype-core/src/language/ruby/index.ts b/packages/quicktype-core/src/language/ruby/index.ts index 42868baa7..1776a3964 100644 --- a/packages/quicktype-core/src/language/ruby/index.ts +++ b/packages/quicktype-core/src/language/ruby/index.ts @@ -1,13 +1,13 @@ import unicode from "unicode-properties"; -import { type Sourcelike} from "../../Source"; +import { type Sourcelike } from "../../Source"; import { modifySource } from "../../Source"; import { type Name } from "../../Naming"; import { Namer } from "../../Naming"; import { type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; import { ConvenienceRenderer } from "../../ConvenienceRenderer"; import { TargetLanguage } from "../../TargetLanguage"; -import { type Option, type OptionValues} from "../../RendererOptions"; +import { type Option, type OptionValues } from "../../RendererOptions"; import { BooleanOption, EnumOption, getOptionValues, StringOption } from "../../RendererOptions"; import * as keywords from "./keywords"; @@ -30,11 +30,11 @@ import { escapeNonPrintableMapper, intToHex, snakeCase, - isLetterOrUnderscore, + isLetterOrUnderscore } from "../../support/Strings"; import { type RenderContext } from "../../Renderer"; -function unicodeEscape (codePoint: number): string { +function unicodeEscape(codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; } @@ -51,43 +51,43 @@ export const rubyOptions = { strictness: new EnumOption("strictness", "Type strictness", [ ["strict", Strictness.Strict], ["coercible", Strictness.Coercible], - ["none", Strictness.None], + ["none", Strictness.None] ]), - namespace: new StringOption("namespace", "Specify a wrapping Namespace", "NAME", "", "secondary"), + namespace: new StringOption("namespace", "Specify a wrapping Namespace", "NAME", "", "secondary") }; export class RubyTargetLanguage extends TargetLanguage { - constructor () { + public constructor() { super("Ruby", ["ruby"], "rb"); } - protected getOptions (): Array> { + protected getOptions(): Array> { return [rubyOptions.justTypes, rubyOptions.strictness, rubyOptions.namespace]; } - get supportsOptionalClassProperties (): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } - protected get defaultIndentation (): string { + protected get defaultIndentation(): string { return " "; } - protected makeRenderer (renderContext: RenderContext, untypedOptionValues: { [name: string]: any, }): RubyRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): RubyRenderer { return new RubyRenderer(this, renderContext, getOptionValues(rubyOptions, untypedOptionValues)); } } const isStartCharacter = isLetterOrUnderscore; -function isPartCharacter (utf16Unit: number): boolean { +function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } const legalizeName = legalizeCharacters(isPartCharacter); -function simpleNameStyle (original: string, uppercase: boolean): string { +function simpleNameStyle(original: string, uppercase: boolean): string { if (/^[0-9]+$/.test(original)) { original = original + "N"; } @@ -101,11 +101,11 @@ function simpleNameStyle (original: string, uppercase: boolean): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter, + isStartCharacter ); } -function memberNameStyle (original: string): string { +function memberNameStyle(original: string): string { const words = splitIntoWords(original); return combineWords( words, @@ -115,56 +115,56 @@ function memberNameStyle (original: string): string { allLowerWordStyle, allLowerWordStyle, "_", - isStartCharacter, + isStartCharacter ); } export class RubyRenderer extends ConvenienceRenderer { - constructor ( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues, + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); } - protected get commentLineStart (): string { + protected get commentLineStart(): string { return "# "; } - protected get needsTypeDeclarationBeforeUse (): boolean { + protected get needsTypeDeclarationBeforeUse(): boolean { return true; } - protected canBeForwardDeclared (t: Type): boolean { + protected canBeForwardDeclared(t: Type): boolean { return "class" === t.kind; } - protected forbiddenNamesForGlobalNamespace (): string[] { + protected forbiddenNamesForGlobalNamespace(): string[] { return keywords.globals.concat(["Types", "JSON", "Dry", "Constructor", "Self"]); } - protected forbiddenForObjectProperties (_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { return { names: forbiddenForObjectProperties, includeGlobalForbidden: true }; } - protected makeNamedTypeNamer (): Namer { + protected makeNamedTypeNamer(): Namer { return new Namer("types", n => simpleNameStyle(n, true), []); } - protected namerForObjectProperty (): Namer { + protected namerForObjectProperty(): Namer { return new Namer("properties", memberNameStyle, []); } - protected makeUnionMemberNamer (): Namer { + protected makeUnionMemberNamer(): Namer { return new Namer("properties", memberNameStyle, []); } - protected makeEnumCaseNamer (): Namer { + protected makeEnumCaseNamer(): Namer { return new Namer("enum-cases", n => simpleNameStyle(n, true), []); } - private dryType (t: Type, isOptional = false): Sourcelike { + private dryType(t: Type, isOptional = false): Sourcelike { const optional = isOptional ? ".optional" : ""; return matchType( t, @@ -185,11 +185,11 @@ export class RubyRenderer extends ConvenienceRenderer { } return ["Types.Instance(", this.nameForNamedType(unionType), ")", optional]; - }, + } ); } - private exampleUse (t: Type, exp: Sourcelike, depth = 6, optional = false): Sourcelike { + private exampleUse(t: Type, exp: Sourcelike, depth = 6, optional = false): Sourcelike { if (depth-- <= 0) { return exp; } @@ -206,7 +206,7 @@ export class RubyRenderer extends ConvenienceRenderer { _stringType => exp, arrayType => this.exampleUse(arrayType.items, [exp, safeNav, ".first"], depth), classType => { - let info: { name: Name, prop: ClassProperty, } | undefined; + let info: { name: Name; prop: ClassProperty } | undefined; this.forEachClassProperty(classType, "none", (name, _json, prop) => { if (["class", "map", "array"].includes(prop.type.kind)) { info = { name, prop }; @@ -220,7 +220,7 @@ export class RubyRenderer extends ConvenienceRenderer { return exp; }, - mapType => this.exampleUse(mapType.values, [exp, safeNav, "[\"…\"]"], depth), + mapType => this.exampleUse(mapType.values, [exp, safeNav, '["…"]'], depth), enumType => { let name: Name | undefined; // FIXME: This is a terrible way to get the first enum case name. @@ -246,12 +246,12 @@ export class RubyRenderer extends ConvenienceRenderer { } return exp; - }, + } ); } - private jsonSample (t: Type): Sourcelike { - function inner () { + private jsonSample(t: Type): Sourcelike { + function inner() { if (t instanceof ArrayType) { return "[…]"; } else if (t instanceof MapType) { @@ -266,7 +266,7 @@ export class RubyRenderer extends ConvenienceRenderer { return `"${inner()}"`; } - private fromDynamic (t: Type, e: Sourcelike, optional = false, castPrimitives = false): Sourcelike { + private fromDynamic(t: Type, e: Sourcelike, optional = false, castPrimitives = false): Sourcelike { const primitiveCast = [this.dryType(t, optional), "[", e, "]"]; const primitive = castPrimitives ? primitiveCast : e; const safeAccess = optional ? "&" : ""; @@ -290,7 +290,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.fromDynamic(mapType.values, "v", false, true), "] }", safeAccess, - ".to_h", + ".to_h" ], enumType => { const expression = ["Types::", this.nameForNamedType(enumType), "[", e, "]"]; @@ -304,11 +304,11 @@ export class RubyRenderer extends ConvenienceRenderer { const expression = [this.nameForNamedType(unionType), ".from_dynamic!(", e, ")"]; return optional ? [e, " ? ", expression, " : nil"] : expression; - }, + } ); } - private toDynamic (t: Type, e: Sourcelike, optional = false): Sourcelike { + private toDynamic(t: Type, e: Sourcelike, optional = false): Sourcelike { if (this.marshalsImplicitlyToDynamic(t)) { return e; } @@ -336,11 +336,11 @@ export class RubyRenderer extends ConvenienceRenderer { } return [e, optional ? "&" : "", ".to_dynamic"]; - }, + } ); } - private marshalsImplicitlyToDynamic (t: Type): boolean { + private marshalsImplicitlyToDynamic(t: Type): boolean { return matchType( t, _anyType => true, @@ -360,14 +360,14 @@ export class RubyRenderer extends ConvenienceRenderer { } return false; - }, + } ); } // This is only to be used to allow class properties to possibly // marshal implicitly. They are allowed to do this because they will // be checked in Dry::Struct.new - private propertyTypeMarshalsImplicitlyFromDynamic (t: Type): boolean { + private propertyTypeMarshalsImplicitlyFromDynamic(t: Type): boolean { return matchType( t, _anyType => true, @@ -388,17 +388,17 @@ export class RubyRenderer extends ConvenienceRenderer { } return false; - }, + } ); } - private emitBlock (source: Sourcelike, emit: () => void) { + private emitBlock(source: Sourcelike, emit: () => void) { this.emitLine(source); this.indent(emit); this.emitLine("end"); } - private emitModule (emit: () => void) { + private emitModule(emit: () => void) { const emitModuleInner = (moduleName: string) => { const [firstModule, ...subModules] = moduleName.split("::"); if (subModules.length > 0) { @@ -417,7 +417,7 @@ export class RubyRenderer extends ConvenienceRenderer { } } - private emitClass (c: ClassType, className: Name) { + private emitClass(c: ClassType, className: Name) { this.emitDescription(this.descriptionForType(c)); this.emitBlock(["class ", className, " < Dry::Struct"], () => { let table: Sourcelike[][] = []; @@ -427,7 +427,7 @@ export class RubyRenderer extends ConvenienceRenderer { const description = this.descriptionForClassProperty(c, jsonName); const attribute = [ ["attribute :", name, ","], - [" ", this.dryType(p.type), p.isOptional ? ".optional" : ""], + [" ", this.dryType(p.type), p.isOptional ? ".optional" : ""] ]; if (description !== undefined) { if (table.length > 0) { @@ -462,20 +462,20 @@ export class RubyRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const dynamic = p.isOptional ? // If key is not found in hash, this will be nil - `d["${stringEscape(jsonName)}"]` + `d["${stringEscape(jsonName)}"]` : // This will raise a runtime error if the key is not found in the hash - `d.fetch("${stringEscape(jsonName)}")`; + `d.fetch("${stringEscape(jsonName)}")`; if (this.propertyTypeMarshalsImplicitlyFromDynamic(p.type)) { inits.push([ [name, ": "], - [dynamic, ","], + [dynamic, ","] ]); } else { const expression = this.fromDynamic(p.type, dynamic, p.isOptional); inits.push([ [name, ": "], - [expression, ","], + [expression, ","] ]); } }); @@ -509,7 +509,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitEnum (e: EnumType, enumName: Name) { + private emitEnum(e: EnumType, enumName: Name) { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["module ", enumName], () => { const table: Sourcelike[][] = []; @@ -520,7 +520,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitUnion (u: UnionType, unionName: Name) { + private emitUnion(u: UnionType, unionName: Name) { this.emitDescription(this.descriptionForType(u)); this.emitBlock(["class ", unionName, " < Dry::Struct"], () => { const table: Sourcelike[][] = []; @@ -557,7 +557,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitLine("end"); } }); - this.emitLine("raise \"Invalid union\""); + this.emitLine('raise "Invalid union"'); }); this.ensureBlankLine(); @@ -592,7 +592,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitTypesModule () { + private emitTypesModule() { this.emitBlock(["module Types"], () => { this.emitLine("include Dry.Types(default: :nominal)"); @@ -607,7 +607,7 @@ export class RubyRenderer extends ConvenienceRenderer { bool: has.bool || t.kind === "bool", hash: has.hash || t.kind === "map" || t.kind === "class", string: has.string || t.kind === "string" || t.kind === "enum", - double: has.double || t.kind === "double", + double: has.double || t.kind === "double" }; }); if (has.int) declarations.push([["Integer"], [` = ${this._options.strictness}Integer`]]); @@ -621,7 +621,7 @@ export class RubyRenderer extends ConvenienceRenderer { if (has.double) declarations.push([ ["Double"], - [` = ${this._options.strictness}Float | ${this._options.strictness}Integer`], + [` = ${this._options.strictness}Float | ${this._options.strictness}Integer`] ]); } @@ -640,7 +640,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - protected emitSourceStructure () { + protected emitSourceStructure() { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else if (!this._options.justTypes) { @@ -682,7 +682,7 @@ export class RubyRenderer extends ConvenienceRenderer { "leading-and-interposing", (c: ClassType, n: Name) => this.emitClass(c, n), (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n), + (u, n) => this.emitUnion(u, n) ); if (!this._options.justTypes) { @@ -702,7 +702,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitLine( self, " = ", - this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)"), + this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") ); this.emitBlock([self, ".define_singleton_method(:to_json) do"], () => { this.emitLine("JSON.generate(", this.toDynamic(topLevel, "self"), ")"); @@ -710,7 +710,7 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitLine(self); } else { this.emitLine( - this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)"), + this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") ); } }); @@ -721,7 +721,7 @@ export class RubyRenderer extends ConvenienceRenderer { classDeclaration(); }); }, - t => this.namedTypeToNameForTopLevel(t) === undefined, + t => this.namedTypeToNameForTopLevel(t) === undefined ); } }); diff --git a/packages/quicktype-core/src/rewrites/CombineClasses.ts b/packages/quicktype-core/src/rewrites/CombineClasses.ts index a89826f7c..4dac053fb 100644 --- a/packages/quicktype-core/src/rewrites/CombineClasses.ts +++ b/packages/quicktype-core/src/rewrites/CombineClasses.ts @@ -1,4 +1,4 @@ -import { type Type, type ClassProperty} from "../Type"; +import { type Type, type ClassProperty } from "../Type"; import { ClassType, setOperationCasesEqual } from "../Type"; import { nonNullTypeCases, combineTypeAttributesOfTypes } from "../TypeUtils"; @@ -18,11 +18,11 @@ interface Clique { // FIXME: Allow some type combinations to unify, like different enums, // enums with strings, integers with doubles, maps with objects of // the correct type. -function typeSetsCanBeCombined (s1: Iterable, s2: Iterable): boolean { +function typeSetsCanBeCombined(s1: Iterable, s2: Iterable): boolean { return setOperationCasesEqual(s1, s2, true, (a, b) => a.structurallyCompatible(b, true)); } -function canBeCombined (c1: ClassType, c2: ClassType, onlyWithSameProperties: boolean): boolean { +function canBeCombined(c1: ClassType, c2: ClassType, onlyWithSameProperties: boolean): boolean { const p1 = c1.getProperties(); const p2 = c2.getProperties(); if (onlyWithSameProperties) { @@ -83,7 +83,7 @@ function canBeCombined (c1: ClassType, c2: ClassType, onlyWithSameProperties: bo return true; } -function tryAddToClique (c: ClassType, clique: Clique, onlyWithSameProperties: boolean): boolean { +function tryAddToClique(c: ClassType, clique: Clique, onlyWithSameProperties: boolean): boolean { for (const prototype of clique.prototypes) { if (prototype.structurallyCompatible(c)) { clique.members.push(c); @@ -102,13 +102,13 @@ function tryAddToClique (c: ClassType, clique: Clique, onlyWithSameProperties: b return false; } -function findSimilarityCliques ( +function findSimilarityCliques( graph: TypeGraph, onlyWithSameProperties: boolean, - includeFixedClasses: boolean, + includeFixedClasses: boolean ): ClassType[][] { const classCandidates = Array.from(graph.allNamedTypesSeparated().objects).filter( - o => o instanceof ClassType && (includeFixedClasses || !o.isFixed), + o => o instanceof ClassType && (includeFixedClasses || !o.isFixed) ) as ClassType[]; const cliques: Clique[] = []; @@ -138,22 +138,22 @@ function findSimilarityCliques ( return cliques.map(clique => clique.members).filter(cl => cl.length > 1); } -export function combineClasses ( +export function combineClasses( ctx: RunContext, graph: TypeGraph, alphabetizeProperties: boolean, conflateNumbers: boolean, onlyWithSameProperties: boolean, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): TypeGraph { const cliques = ctx.time(" find similarity cliques", () => - findSimilarityCliques(graph, onlyWithSameProperties, false), + findSimilarityCliques(graph, onlyWithSameProperties, false) ); - function makeCliqueClass ( + function makeCliqueClass( clique: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef, + forwardingRef: TypeRef ): TypeRef { assert(clique.size > 0, "Clique can't be empty"); const attributes = combineTypeAttributesOfTypes("union", clique); @@ -163,7 +163,7 @@ export function combineClasses ( builder, unionBuilderForUnification(builder, false, false, conflateNumbers), conflateNumbers, - forwardingRef, + forwardingRef ); } @@ -173,6 +173,6 @@ export function combineClasses ( alphabetizeProperties, cliques, debugPrintReconstitution, - makeCliqueClass, + makeCliqueClass ); } diff --git a/packages/quicktype-core/src/rewrites/ExpandStrings.ts b/packages/quicktype-core/src/rewrites/ExpandStrings.ts index 7f2bff226..0482f0032 100644 --- a/packages/quicktype-core/src/rewrites/ExpandStrings.ts +++ b/packages/quicktype-core/src/rewrites/ExpandStrings.ts @@ -6,7 +6,7 @@ import { setUnion, setIntersect, setIsSuperset, - areEqual, + areEqual } from "collection-utils"; import { type PrimitiveType } from "../Type"; @@ -30,31 +30,31 @@ interface EnumInfo { numValues: number; } -function isOwnEnum ({ numValues, cases }: EnumInfo): boolean { +function isOwnEnum({ numValues, cases }: EnumInfo): boolean { return numValues >= MIN_LENGTH_FOR_ENUM && cases.size < Math.sqrt(numValues); } -function enumCasesOverlap ( +function enumCasesOverlap( newCases: ReadonlySet, existingCases: ReadonlySet, - newAreSubordinate: boolean, + newAreSubordinate: boolean ): boolean { const smaller = newAreSubordinate ? newCases.size : Math.min(newCases.size, existingCases.size); const overlap = setIntersect(newCases, existingCases).size; return overlap >= smaller * REQUIRED_OVERLAP; } -function isAlwaysEmptyString (cases: string[]): boolean { +function isAlwaysEmptyString(cases: string[]): boolean { return cases.length === 1 && cases[0] === ""; } -export function expandStrings (ctx: RunContext, graph: TypeGraph, inference: EnumInference): TypeGraph { +export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: EnumInference): TypeGraph { const stringTypeMapping = ctx.stringTypeMapping; const allStrings = Array.from(graph.allTypesUnordered()).filter( - t => t.kind === "string" && stringTypesForType(t as PrimitiveType).isRestricted, + t => t.kind === "string" && stringTypesForType(t as PrimitiveType).isRestricted ) as PrimitiveType[]; - function makeEnumInfo (t: PrimitiveType): EnumInfo | undefined { + function makeEnumInfo(t: PrimitiveType): EnumInfo | undefined { const stringTypes = stringTypesForType(t); const mappedStringTypes = stringTypes.applyStringTypeMapping(stringTypeMapping); if (!mappedStringTypes.isRestricted) return undefined; @@ -85,7 +85,7 @@ export function expandStrings (ctx: RunContext, graph: TypeGraph, inference: Enu enumInfos.set(t, enumInfo); } - function findOverlap (newCases: ReadonlySet, newAreSubordinate: boolean): number { + function findOverlap(newCases: ReadonlySet, newAreSubordinate: boolean): number { return enumSets.findIndex(s => enumCasesOverlap(newCases, s, newAreSubordinate)); } @@ -139,10 +139,10 @@ export function expandStrings (ctx: RunContext, graph: TypeGraph, inference: Enu } } - function replaceString ( + function replaceString( group: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef, + forwardingRef: TypeRef ): TypeRef { assert(group.size === 1); const t = defined(iterableFirst(group)); @@ -191,6 +191,6 @@ export function expandStrings (ctx: RunContext, graph: TypeGraph, inference: Enu false, allStrings.map(t => [t]), ctx.debugPrintReconstitution, - replaceString, + replaceString ); } diff --git a/packages/quicktype-core/src/rewrites/FlattenStrings.ts b/packages/quicktype-core/src/rewrites/FlattenStrings.ts index 18ce4da1b..fa43717e5 100644 --- a/packages/quicktype-core/src/rewrites/FlattenStrings.ts +++ b/packages/quicktype-core/src/rewrites/FlattenStrings.ts @@ -10,23 +10,23 @@ import { combineTypeAttributes } from "../attributes/TypeAttributes"; // A union needs replacing if it contains more than one string type, one of them being // a basic string type. -function unionNeedsReplacing (u: UnionType): ReadonlySet | undefined { +function unionNeedsReplacing(u: UnionType): ReadonlySet | undefined { const stringMembers = u.stringTypeMembers; if (stringMembers.size <= 1) return undefined; const stringType = u.findMember("string"); if (stringType === undefined) return undefined; assert( !stringTypesForType(stringType as PrimitiveType).isRestricted, - "We must only flatten strings if we have no restriced strings", + "We must only flatten strings if we have no restriced strings" ); return stringMembers; } // Replaces all string types in an enum with the basic string type. -function replaceUnion ( +function replaceUnion( group: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef, + forwardingRef: TypeRef ): TypeRef { assert(group.size === 1); const u = defined(iterableFirst(group)); @@ -42,7 +42,7 @@ function replaceUnion ( return builder.getStringType( combineTypeAttributes("union", stringAttributes, u.getAttributes()), undefined, - forwardingRef, + forwardingRef ); } @@ -50,10 +50,10 @@ function replaceUnion ( return builder.getUnionType(u.getAttributes(), new Set(types), forwardingRef); } -export function flattenStrings ( +export function flattenStrings( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): TypeGraph { const allUnions = graph.allNamedTypesSeparated().unions; const unionsToReplace = Array.from(allUnions) @@ -65,6 +65,6 @@ export function flattenStrings ( false, unionsToReplace, debugPrintReconstitution, - replaceUnion, + replaceUnion ); } diff --git a/packages/quicktype-core/src/rewrites/FlattenUnions.ts b/packages/quicktype-core/src/rewrites/FlattenUnions.ts index b9ef1d41e..a834002e8 100644 --- a/packages/quicktype-core/src/rewrites/FlattenUnions.ts +++ b/packages/quicktype-core/src/rewrites/FlattenUnions.ts @@ -1,8 +1,8 @@ import { setFilter, iterableSome } from "collection-utils"; -import { type TypeGraph, type TypeRef} from "../TypeGraph"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; import { derefTypeRef } from "../TypeGraph"; -import { type Type} from "../Type"; +import { type Type } from "../Type"; import { UnionType, IntersectionType } from "../Type"; import { makeGroupsToFlatten } from "../TypeUtils"; import { assert } from "../support/Support"; @@ -12,16 +12,16 @@ import { unifyTypes, UnifyUnionBuilder } from "../UnifyClasses"; import { messageAssert } from "../Messages"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; -export function flattenUnions ( +export function flattenUnions( graph: TypeGraph, stringTypeMapping: StringTypeMapping, conflateNumbers: boolean, makeObjectTypes: boolean, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): [TypeGraph, boolean] { let needsRepeat = false; - function replace (types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { + function replace(types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { const unionBuilder = new UnifyUnionBuilder(builder, makeObjectTypes, true, trefs => { assert(trefs.length > 0, "Must have at least one type to build union"); trefs = trefs.map(tref => builder.reconstituteType(derefTypeRef(tref, graph))); diff --git a/packages/quicktype-core/src/rewrites/InferMaps.ts b/packages/quicktype-core/src/rewrites/InferMaps.ts index 0092d1dbf..43e30182c 100644 --- a/packages/quicktype-core/src/rewrites/InferMaps.ts +++ b/packages/quicktype-core/src/rewrites/InferMaps.ts @@ -1,6 +1,6 @@ import { iterableFirst, iterableEvery, setMap } from "collection-utils"; -import { type Type, type ClassProperty} from "../Type"; +import { type Type, type ClassProperty } from "../Type"; import { ClassType, setOperationCasesEqual, isPrimitiveStringTypeKind } from "../Type"; import { removeNullFromType } from "../TypeUtils"; import { defined, panic } from "../support/Support"; @@ -8,7 +8,7 @@ import { type TypeGraph, type TypeRef } from "../TypeGraph"; import { type StringTypeMapping } from "../TypeBuilder"; import { type GraphRewriteBuilder } from "../GraphRewriting"; import { unifyTypes, unionBuilderForUnification } from "../UnifyClasses"; -import { type MarkovChain} from "../MarkovChain"; +import { type MarkovChain } from "../MarkovChain"; import { load, evaluate } from "../MarkovChain"; const mapSizeThreshold = 20; @@ -16,7 +16,7 @@ const stringMapSizeThreshold = 50; let markovChain: MarkovChain | undefined = undefined; -function nameProbability (name: string): number { +function nameProbability(name: string): number { if (markovChain === undefined) { markovChain = load(); } @@ -24,7 +24,7 @@ function nameProbability (name: string): number { return evaluate(markovChain, name); } -function shouldBeMap (properties: ReadonlyMap): ReadonlySet | undefined { +function shouldBeMap(properties: ReadonlyMap): ReadonlySet | undefined { // Only classes with a certain number of properties are inferred // as maps. const numProperties = properties.size; @@ -108,16 +108,16 @@ function shouldBeMap (properties: ReadonlyMap): ReadonlyS return allCases; } -export function inferMaps ( +export function inferMaps( graph: TypeGraph, stringTypeMapping: StringTypeMapping, conflateNumbers: boolean, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): TypeGraph { - function replaceClass ( + function replaceClass( setOfOneClass: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef, + forwardingRef: TypeRef ): TypeRef { const c = defined(iterableFirst(setOfOneClass)); const properties = c.getProperties(); @@ -140,9 +140,9 @@ export function inferMaps ( c.getAttributes(), builder, unionBuilderForUnification(builder, false, false, conflateNumbers), - conflateNumbers, + conflateNumbers ), - forwardingRef, + forwardingRef ); } @@ -156,6 +156,6 @@ export function inferMaps ( false, classesToReplace.map(c => [c]), debugPrintReconstitution, - replaceClass, + replaceClass ); } diff --git a/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts b/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts index e225c3c42..99acbc145 100644 --- a/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts +++ b/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts @@ -7,34 +7,34 @@ import { type ObjectType, type ClassProperty } from "../Type"; import { defined } from "../support/Support"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; -export function replaceObjectType ( +export function replaceObjectType( graph: TypeGraph, stringTypeMapping: StringTypeMapping, _conflateNumbers: boolean, leaveFullObjects: boolean, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): TypeGraph { - function replace ( + function replace( setOfOneType: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef, + forwardingRef: TypeRef ): TypeRef { const o = defined(iterableFirst(setOfOneType)); const attributes = o.getAttributes(); const properties = o.getProperties(); const additionalProperties = o.getAdditionalProperties(); - function reconstituteProperties (): ReadonlyMap { + function reconstituteProperties(): ReadonlyMap { return mapMap(properties, cp => - builder.makeClassProperty(builder.reconstituteTypeRef(cp.typeRef), cp.isOptional), + builder.makeClassProperty(builder.reconstituteTypeRef(cp.typeRef), cp.isOptional) ); } - function makeClass (): TypeRef { + function makeClass(): TypeRef { return builder.getUniqueClassType(attributes, true, reconstituteProperties(), forwardingRef); } - function reconstituteAdditionalProperties (): TypeRef { + function reconstituteAdditionalProperties(): TypeRef { return builder.reconstituteType(defined(additionalProperties)); } diff --git a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts index 22f2984cb..a3a3016be 100644 --- a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts +++ b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts @@ -9,7 +9,7 @@ import { setMap, iterableFind, setIntersect, - setUnionInto, + setUnionInto } from "collection-utils"; import { type TypeGraph, type TypeRef } from "../TypeGraph"; @@ -17,10 +17,7 @@ import { type StringTypeMapping, type TypeBuilder } from "../TypeBuilder"; import { type GraphRewriteBuilder, type TypeLookerUp } from "../GraphRewriting"; import { type UnionTypeProvider, type TypeAttributeMap } from "../UnionBuilder"; import { UnionBuilder } from "../UnionBuilder"; -import { - type Type, - type PrimitiveTypeKind, - type TypeKind} from "../Type"; +import { type Type, type PrimitiveTypeKind, type TypeKind } from "../Type"; import { IntersectionType, UnionType, @@ -28,32 +25,28 @@ import { isPrimitiveTypeKind, isNumberTypeKind, GenericClassProperty, - ObjectType, + ObjectType } from "../Type"; import { setOperationMembersRecursively, matchTypeExhaustive, makeGroupsToFlatten } from "../TypeUtils"; import { assert, defined, panic, mustNotHappen } from "../support/Support"; -import { - type TypeAttributes} from "../attributes/TypeAttributes"; -import { - combineTypeAttributes, - emptyTypeAttributes, - makeTypeAttributesInferred, -} from "../attributes/TypeAttributes"; +import { type TypeAttributes } from "../attributes/TypeAttributes"; +import { combineTypeAttributes, emptyTypeAttributes, makeTypeAttributesInferred } from "../attributes/TypeAttributes"; -function canResolve (t: IntersectionType): boolean { +function canResolve(t: IntersectionType): boolean { const members = setOperationMembersRecursively(t, undefined)[0]; if (members.size <= 1) return true; return iterableEvery(members, m => !(m instanceof UnionType) || m.isCanonical); } -function attributesForTypes (types: ReadonlySet): TypeAttributeMap { +function attributesForTypes(types: ReadonlySet): TypeAttributeMap { return mapMapEntries(types.entries(), t => [t.kind, t.getAttributes()] as [T, TypeAttributes]); } type PropertyMap = Map>>; class IntersectionAccumulator -implements UnionTypeProvider, [PropertyMap, ReadonlySet | undefined] | undefined> { + implements UnionTypeProvider, [PropertyMap, ReadonlySet | undefined] | undefined> +{ private _primitiveTypes: Set | undefined; private readonly _primitiveAttributes: TypeAttributeMap = new Map(); @@ -81,7 +74,7 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet private _lostTypeAttributes = false; - private updatePrimitiveTypes (members: Iterable): void { + private updatePrimitiveTypes(members: Iterable): void { const types = setFilter(members, t => isPrimitiveTypeKind(t.kind)); const attributes = attributesForTypes(types); mapMergeWithInto(this._primitiveAttributes, (a, b) => combineTypeAttributes("intersect", a, b), attributes); @@ -103,7 +96,7 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet } } - private updateArrayItemTypes (members: Iterable): void { + private updateArrayItemTypes(members: Iterable): void { const maybeArray = iterableFind(members, t => t instanceof ArrayType) as ArrayType | undefined; if (maybeArray === undefined) { this._arrayItemTypes = false; @@ -119,7 +112,7 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet } } - private updateObjectProperties (members: Iterable): void { + private updateObjectProperties(members: Iterable): void { const maybeObject = iterableFind(members, t => t instanceof ObjectType) as ObjectType | undefined; if (maybeObject === undefined) { this._objectProperties = undefined; @@ -130,7 +123,7 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet this._objectAttributes = combineTypeAttributes( "intersect", this._objectAttributes, - maybeObject.getAttributes(), + maybeObject.getAttributes() ); const objectAdditionalProperties = maybeObject.getAdditionalProperties(); @@ -141,7 +134,7 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet const allPropertyNames = setUnionInto( new Set(this._objectProperties.keys()), - maybeObject.getProperties().keys(), + maybeObject.getProperties().keys() ); for (const name of allPropertyNames) { const existing = defined(this._objectProperties).get(name); @@ -150,13 +143,13 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet if (existing !== undefined && newProperty !== undefined) { const cp = new GenericClassProperty( existing.typeData.add(newProperty.type), - existing.isOptional && newProperty.isOptional, + existing.isOptional && newProperty.isOptional ); defined(this._objectProperties).set(name, cp); } else if (existing !== undefined && objectAdditionalProperties !== undefined) { const cp = new GenericClassProperty( existing.typeData.add(objectAdditionalProperties), - existing.isOptional, + existing.isOptional ); defined(this._objectProperties).set(name, cp); } else if (existing !== undefined) { @@ -180,13 +173,13 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet } } - private addUnionSet (members: Iterable): void { + private addUnionSet(members: Iterable): void { this.updatePrimitiveTypes(members); this.updateArrayItemTypes(members); this.updateObjectProperties(members); } - addType (t: Type): TypeAttributes { + public addType(t: Type): TypeAttributes { let attributes = t.getAttributes(); matchTypeExhaustive( t, @@ -209,16 +202,16 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet unionType => { attributes = combineTypeAttributes( "intersect", - [attributes].concat(Array.from(unionType.members).map(m => m.getAttributes())), + [attributes].concat(Array.from(unionType.members).map(m => m.getAttributes())) ); this.addUnionSet(unionType.members); }, - transformedStringType => this.addUnionSet([transformedStringType]), + transformedStringType => this.addUnionSet([transformedStringType]) ); return makeTypeAttributesInferred(attributes); } - get arrayData (): ReadonlySet { + public get arrayData(): ReadonlySet { if (this._arrayItemTypes === undefined || this._arrayItemTypes === false) { return panic("This should not be called if the type can't be an array"); } @@ -226,7 +219,7 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet return this._arrayItemTypes; } - get objectData (): [PropertyMap, ReadonlySet | undefined] | undefined { + public get objectData(): [PropertyMap, ReadonlySet | undefined] | undefined { if (this._objectProperties === undefined) { assert(this._additionalPropertyTypes === undefined); return undefined; @@ -235,13 +228,13 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet return [this._objectProperties, this._additionalPropertyTypes]; } - get enumCases (): ReadonlySet { + public get enumCases(): ReadonlySet { return panic("We don't support enums in intersections"); } - getMemberKinds (): TypeAttributeMap { + public getMemberKinds(): TypeAttributeMap { const kinds: TypeAttributeMap = mapMap(defined(this._primitiveTypes).entries(), k => - defined(this._primitiveAttributes.get(k)), + defined(this._primitiveAttributes.get(k)) ); const maybeDoubleAttributes = this._primitiveAttributes.get("double"); // If double was eliminated, add its attributes to integer @@ -267,19 +260,19 @@ implements UnionTypeProvider, [PropertyMap, ReadonlySet return kinds; } - get lostTypeAttributes (): boolean { + public get lostTypeAttributes(): boolean { return this._lostTypeAttributes; } } class IntersectionUnionBuilder extends UnionBuilder< -TypeBuilder & TypeLookerUp, -ReadonlySet, -[PropertyMap, ReadonlySet | undefined] | undefined + TypeBuilder & TypeLookerUp, + ReadonlySet, + [PropertyMap, ReadonlySet | undefined] | undefined > { private _createdNewIntersections = false; - private makeIntersection (members: ReadonlySet, attributes: TypeAttributes): TypeRef { + private makeIntersection(members: ReadonlySet, attributes: TypeAttributes): TypeRef { const reconstitutedMembers = setMap(members, t => this.typeBuilder.reconstituteTypeRef(t.typeRef)); const first = defined(iterableFirst(reconstitutedMembers)); @@ -292,14 +285,14 @@ ReadonlySet, return this.typeBuilder.getUniqueIntersectionType(attributes, reconstitutedMembers); } - get createdNewIntersections (): boolean { + public get createdNewIntersections(): boolean { return this._createdNewIntersections; } - protected makeObject ( + protected makeObject( maybeData: [PropertyMap, ReadonlySet | undefined] | undefined, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined, + forwardingRef: TypeRef | undefined ): TypeRef { if (maybeData === undefined) { return panic("Either properties or additional properties must be given to make an object type"); @@ -307,7 +300,7 @@ ReadonlySet, const [propertyTypes, maybeAdditionalProperties] = maybeData; const properties = mapMap(propertyTypes, cp => - this.typeBuilder.makeClassProperty(this.makeIntersection(cp.typeData, emptyTypeAttributes), cp.isOptional), + this.typeBuilder.makeClassProperty(this.makeIntersection(cp.typeData, emptyTypeAttributes), cp.isOptional) ); const additionalProperties = maybeAdditionalProperties === undefined @@ -316,10 +309,10 @@ ReadonlySet, return this.typeBuilder.getUniqueObjectType(typeAttributes, properties, additionalProperties, forwardingRef); } - protected makeArray ( + protected makeArray( arrays: ReadonlySet, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined, + forwardingRef: TypeRef | undefined ): TypeRef { // FIXME: attributes const itemsType = this.makeIntersection(arrays, emptyTypeAttributes); @@ -328,18 +321,18 @@ ReadonlySet, } } -export function resolveIntersections ( +export function resolveIntersections( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean, + debugPrintReconstitution: boolean ): [TypeGraph, boolean] { let needsRepeat = false; - function replace (types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { + function replace(types: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef): TypeRef { const intersections = setFilter(types, t => t instanceof IntersectionType) as Set; const [members, intersectionAttributes] = setOperationMembersRecursively( Array.from(intersections), - "intersect", + "intersect" ); if (members.size === 0) { const t = builder.getPrimitiveType("any", intersectionAttributes, forwardingRef); @@ -354,8 +347,8 @@ export function resolveIntersections ( const extraAttributes = makeTypeAttributesInferred( combineTypeAttributes( "intersect", - Array.from(members).map(t => accumulator.addType(t)), - ), + Array.from(members).map(t => accumulator.addType(t)) + ) ); const attributes = combineTypeAttributes("intersect", intersectionAttributes, extraAttributes); @@ -372,7 +365,7 @@ export function resolveIntersections ( // See for example the intersections-nested.schema example. const allIntersections = setFilter( graph.allTypesUnordered(), - t => t instanceof IntersectionType, + t => t instanceof IntersectionType ) as Set; const resolvableIntersections = setFilter(allIntersections, canResolve); const groups = makeGroupsToFlatten(resolvableIntersections, undefined); diff --git a/packages/quicktype-core/src/support/Chance.ts b/packages/quicktype-core/src/support/Chance.ts index 72b58a0fb..74f8162ac 100644 --- a/packages/quicktype-core/src/support/Chance.ts +++ b/packages/quicktype-core/src/support/Chance.ts @@ -1,3 +1,4 @@ +/* eslint-disable */ // Mersenne Twister from https://gist.github.com/banksean/300494 /* A C-program for MT19937, with initialization improved 2002/1/26. @@ -48,7 +49,7 @@ class MersenneTwister { private mti: number; - constructor (seed: number) { + public constructor(seed: number) { if (seed === undefined) { // kept random number same size as time used previously to ensure no unexpected results downstream seed = Math.floor(Math.random() * Math.pow(10, 13)); @@ -68,12 +69,12 @@ class MersenneTwister { } /* initializes mt[N] with a seed */ - private init_genrand (s: number) { + private init_genrand(s: number) { this.mt[0] = s >>> 0; for (this.mti = 1; this.mti < this.N; this.mti++) { - s = this.mt[this.mti - 1] ^ this.mt[this.mti - 1] >>> 30; + s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30); this.mt[this.mti] = - (((s & 0xffff0000) >>> 16) * 1812433253 << 16) + (s & 0x0000ffff) * 1812433253 + this.mti; + ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + this.mti; /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ @@ -84,7 +85,7 @@ class MersenneTwister { } /* generates a random number on [0,0xffffffff]-interval */ - private genrand_int32 () { + private genrand_int32() { let y; let mag01 = [0x0, this.MATRIX_A]; /* mag01[x] = x * MATRIX_A for x=0,1 */ @@ -99,17 +100,17 @@ class MersenneTwister { } for (kk = 0; kk < this.N - this.M; kk++) { - y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK; - this.mt[kk] = this.mt[kk + this.M] ^ y >>> 1 ^ mag01[y & 0x1]; + y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK); + this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1]; } for (; kk < this.N - 1; kk++) { - y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK; - this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ y >>> 1 ^ mag01[y & 0x1]; + y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK); + this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1]; } - y = this.mt[this.N - 1] & this.UPPER_MASK | this.mt[0] & this.LOWER_MASK; - this.mt[this.N - 1] = this.mt[this.M - 1] ^ y >>> 1 ^ mag01[y & 0x1]; + y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK); + this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; this.mti = 0; } @@ -118,15 +119,15 @@ class MersenneTwister { /* Tempering */ y ^= y >>> 11; - y ^= y << 7 & 0x9d2c5680; - y ^= y << 15 & 0xefc60000; + y ^= (y << 7) & 0x9d2c5680; + y ^= (y << 15) & 0xefc60000; y ^= y >>> 18; return y >>> 0; } /* generates a random number on [0,1)-real-interval */ - random () { + random() { return this.genrand_int32() * (1.0 / 4294967296.0); /* divided by 2^32 */ } @@ -136,12 +137,12 @@ class MersenneTwister { export class Chance { private readonly mt: MersenneTwister; - constructor (readonly seed: number) { + public constructor(readonly seed: number) { // If no generator function was provided, use our MT this.mt = new MersenneTwister(this.seed); } - random (): number { + random(): number { return this.mt.random(); } @@ -156,7 +157,7 @@ export class Chance { * @returns {Number} a single random integer number * @throws {RangeError} min cannot be greater than max */ - integer (options: { max: number, min: number, }): number { + integer(options: { max: number; min: number }): number { return Math.floor(this.random() * (options.max - options.min + 1) + options.min); } @@ -171,7 +172,7 @@ export class Chance { * @returns {Number} a single random integer number * @throws {RangeError} min cannot be greater than max */ - natural (options: { max: number, }): number { + natural(options: { max: number }): number { return this.integer({ min: 0, max: options.max }); } @@ -183,18 +184,18 @@ export class Chance { return arr[this.natural({ max: arr.length - 1 })]; } - animal (): string { + animal(): string { // if user does not put in any animal type, will return a random animal regardless const animalTypeArray = ["desert", "forest", "ocean", "zoo", "farm", "pet", "grassland"]; return this.pick(animals[this.pick(animalTypeArray)]); } - city (): string { + city(): string { return this.pick(cities); } } -const animals: { [kind: string]: string[], } = { +const animals: { [kind: string]: string[] } = { // list of ocean animals comes from https://owlcation.com/stem/list-of-ocean-animals ocean: [ "Acantharea", @@ -489,7 +490,7 @@ const animals: { [kind: string]: string[], } = { "Yellow Tube Sponge", "Yellowfin Tuna", "Zebrashark", - "Zooplankton", + "Zooplankton" ], // list of desert, grassland, and forest animals comes from http://www.skyenimals.com/ desert: [ @@ -582,7 +583,7 @@ const animals: { [kind: string]: string[], } = { "Vulture", "Waxwing", "Xerus", - "Zebra", + "Zebra" ], grassland: [ "Aardvark", @@ -725,7 +726,7 @@ const animals: { [kind: string]: string[], } = { "Thornbill", "Thrush", "Toad", - "Tortoise", + "Tortoise" ], forest: [ "Agouti", @@ -921,7 +922,7 @@ const animals: { [kind: string]: string[], } = { "Wolf", "Wombat", "Woodchuck", - "Woodpecker", + "Woodpecker" ], // list of farm animals comes from https://www.buzzle.com/articles/farm-animals-list.html farm: [ @@ -952,7 +953,7 @@ const animals: { [kind: string]: string[], } = { "Silkworm", "Turkey", "Yak", - "Zebu", + "Zebu" ], // list of pet animals comes from https://www.dogbreedinfo.com/pets/pet.htm pet: [ @@ -998,7 +999,7 @@ const animals: { [kind: string]: string[], } = { "Sugar Gliders", "Tarantula", "Turkeys", - "Turtles", + "Turtles" ], // list of zoo animals comes from https://bronxzoo.com/animals zoo: [ @@ -1068,8 +1069,8 @@ const animals: { [kind: string]: string[], } = { "Tufted Puffin", "White Cheeked Gibbon", "White-throated Bee Eater", - "Zebra", - ], + "Zebra" + ] }; // Source: https://en.wikipedia.org/wiki/List_of_population_centers_by_latitude @@ -2170,5 +2171,5 @@ const cities: string[] = [ "Villa Las Estrellas", "Esperanza", "Rothera", - "Concordia", + "Concordia" ]; diff --git a/packages/quicktype-core/src/support/Comments.ts b/packages/quicktype-core/src/support/Comments.ts index d7d8a5194..38dd96415 100644 --- a/packages/quicktype-core/src/support/Comments.ts +++ b/packages/quicktype-core/src/support/Comments.ts @@ -9,13 +9,13 @@ export interface CommentOptions { } interface DescriptionBlockCommentConfig { - descriptionBlock: Sourcelike[]; + descriptionBlock: Sourcelike[]; } interface InlineCommentConfig { - lines: Sourcelike[]; + lines: Sourcelike[]; } type CustomCommentConfig = CommentOptions & { - customLines: Sourcelike[], + customLines: Sourcelike[]; }; export type CommentConfig = DescriptionBlockCommentConfig | InlineCommentConfig | CustomCommentConfig; diff --git a/packages/quicktype-core/src/support/Converters.ts b/packages/quicktype-core/src/support/Converters.ts index a06301747..1e9a46250 100644 --- a/packages/quicktype-core/src/support/Converters.ts +++ b/packages/quicktype-core/src/support/Converters.ts @@ -5,15 +5,15 @@ export enum ConvertersOptions { TopLevel = "top-level" } -export function convertersOption () { +export function convertersOption() { return new EnumOption( "converters", "Which converters to generate (top-level by default)", [ [ConvertersOptions.TopLevel, ConvertersOptions.TopLevel], - [ConvertersOptions.AllObjects, ConvertersOptions.AllObjects], + [ConvertersOptions.AllObjects, ConvertersOptions.AllObjects] ], ConvertersOptions.TopLevel, - "secondary", + "secondary" ); } diff --git a/packages/quicktype-core/src/support/Strings.ts b/packages/quicktype-core/src/support/Strings.ts index 78e1ad378..555b861f3 100644 --- a/packages/quicktype-core/src/support/Strings.ts +++ b/packages/quicktype-core/src/support/Strings.ts @@ -12,9 +12,9 @@ export type NamingStyle = import unicode from "unicode-properties"; -function computeAsciiMap (mapper: (codePoint: number) => string): { - charNoEscapeMap: number[], - charStringMap: string[], +function computeAsciiMap(mapper: (codePoint: number) => string): { + charNoEscapeMap: number[]; + charStringMap: string[]; } { const charStringMap: string[] = []; const charNoEscapeMap: number[] = []; @@ -35,7 +35,7 @@ function computeAsciiMap (mapper: (codePoint: number) => string): { type CodePointPredicate = (codePoint: number) => boolean; -function precomputedCodePointPredicate (p: CodePointPredicate): CodePointPredicate { +function precomputedCodePointPredicate(p: CodePointPredicate): CodePointPredicate { const asciiResults: boolean[] = []; for (let cp = 0; cp < 128; cp++) { asciiResults.push(p(cp)); @@ -47,10 +47,10 @@ function precomputedCodePointPredicate (p: CodePointPredicate): CodePointPredica } // FIXME: This is a copy of code in src/Data/String/Util.js -export function utf16ConcatMap (mapper: (utf16Unit: number) => string): (s: string) => string { +export function utf16ConcatMap(mapper: (utf16Unit: number) => string): (s: string) => string { const { charStringMap, charNoEscapeMap } = computeAsciiMap(mapper); - return function stringConcatMap_inner (s: string): string { + return function stringConcatMap_inner(s: string): string { let cs: string[] | null = null; let start = 0; let i = 0; @@ -81,18 +81,18 @@ export function utf16ConcatMap (mapper: (utf16Unit: number) => string): (s: stri }; } -function isHighSurrogate (cc: number): boolean { +function isHighSurrogate(cc: number): boolean { return cc >= 0xd800 && cc <= 0xdbff; } -function isLowSurrogate (cc: number): boolean { +function isLowSurrogate(cc: number): boolean { return cc >= 0xdc00 && cc <= 0xdfff; } -export function utf32ConcatMap (mapper: (codePoint: number) => string): (s: string) => string { +export function utf32ConcatMap(mapper: (codePoint: number) => string): (s: string) => string { const { charStringMap, charNoEscapeMap } = computeAsciiMap(mapper); - return function stringConcatMap_inner (s: string): string { + return function stringConcatMap_inner(s: string): string { let cs: string[] | null = null; let start = 0; let i = 0; @@ -133,15 +133,15 @@ export function utf32ConcatMap (mapper: (codePoint: number) => string): (s: stri }; } -export function utf16LegalizeCharacters (isLegal: (utf16Unit: number) => boolean): (s: string) => string { - return utf16ConcatMap(u => isLegal(u) ? String.fromCharCode(u) : ""); +export function utf16LegalizeCharacters(isLegal: (utf16Unit: number) => boolean): (s: string) => string { + return utf16ConcatMap(u => (isLegal(u) ? String.fromCharCode(u) : "")); } -export function legalizeCharacters (isLegal: (codePoint: number) => boolean): (s: string) => string { - return utf32ConcatMap(u => u <= 0xffff && isLegal(u) ? String.fromCharCode(u) : ""); +export function legalizeCharacters(isLegal: (codePoint: number) => boolean): (s: string) => string { + return utf32ConcatMap(u => (u <= 0xffff && isLegal(u) ? String.fromCharCode(u) : "")); } -export function repeatString (s: string, n: number): string { +export function repeatString(s: string, n: number): string { assert(n >= 0, "Cannot repeat a string a negative number of times"); if (n === 0) return ""; @@ -163,13 +163,13 @@ export function repeatString (s: string, n: number): string { return result; } -export function intToHex (i: number, width: number): string { +export function intToHex(i: number, width: number): string { let str = i.toString(16); if (str.length >= width) return str; return repeatString("0", width - str.length) + str; } -export function standardUnicodeHexEscape (codePoint: number): string { +export function standardUnicodeHexEscape(codePoint: number): string { if (codePoint <= 0xffff) { return "\\u" + intToHex(codePoint, 4); } else { @@ -177,16 +177,16 @@ export function standardUnicodeHexEscape (codePoint: number): string { } } -export function escapeNonPrintableMapper ( +export function escapeNonPrintableMapper( printablePredicate: (codePoint: number) => boolean, - escaper: (codePoint: number) => string, + escaper: (codePoint: number) => string ): (u: number) => string { - function mapper (u: number): string { + function mapper(u: number): string { switch (u) { case 0x5c: return "\\\\"; case 0x22: - return "\\\""; + return '\\"'; case 0x0a: return "\\n"; case 0x09: @@ -206,75 +206,73 @@ export function escapeNonPrintableMapper ( export const utf16StringEscape = utf16ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape)); export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape)); -export function isPrintable (codePoint: number): boolean { +export function isPrintable(codePoint: number): boolean { if (codePoint > 0xffff) return false; const category = unicode.getCategory(codePoint); - return ( - [ - "Mc", - "No", - "Sk", - "Me", - "Nd", - "Po", - "Lt", - "Pc", - "Sm", - "Zs", - "Lu", - "Pd", - "So", - "Pe", - "Pf", - "Ps", - "Sc", - "Ll", - "Lm", - "Pi", - "Nl", - "Mn", - "Lo", - ].includes(category) - ); -} - -export function isAscii (codePoint: number): boolean { + return [ + "Mc", + "No", + "Sk", + "Me", + "Nd", + "Po", + "Lt", + "Pc", + "Sm", + "Zs", + "Lu", + "Pd", + "So", + "Pe", + "Pf", + "Ps", + "Sc", + "Ll", + "Lm", + "Pi", + "Nl", + "Mn", + "Lo" + ].includes(category); +} + +export function isAscii(codePoint: number): boolean { return codePoint < 128; } -export function isLetter (codePoint: number): boolean { +export function isLetter(codePoint: number): boolean { const category = unicode.getCategory(codePoint); // FIXME: Include Letter, modifier (Lm)? return ["Lu", "Ll", "Lt", "Lo"].includes(category); } -export function isDigit (codePoint: number): boolean { +export function isDigit(codePoint: number): boolean { const category = unicode.getCategory(codePoint); return ["Nd"].includes(category); } -export function isNumeric (codePoint: number): boolean { +export function isNumeric(codePoint: number): boolean { const category = unicode.getCategory(codePoint); return ["No", "Nd", "Nl"].includes(category); } -export function isLetterOrDigit (codePoint: number): boolean { +export function isLetterOrDigit(codePoint: number): boolean { return isLetter(codePoint) || isDigit(codePoint); } -export function isLetterOrUnderscore (codePoint: number): boolean { +export function isLetterOrUnderscore(codePoint: number): boolean { return isLetter(codePoint) || codePoint === 0x5f; } -export function isLetterOrUnderscoreOrDigit (codePoint: number): boolean { +export function isLetterOrUnderscoreOrDigit(codePoint: number): boolean { return isLetterOrUnderscore(codePoint) || isDigit(codePoint); } -export function isWordCharacter (codePoint: number): boolean { +export function isWordCharacter(codePoint: number): boolean { return isLetter(codePoint) || isDigit(codePoint); } -export function trimEnd (str: string): string { +export function trimEnd(str: string): string { const l = str.length; let firstWS = l; for (let i = l - 1; i >= 0; i--) { @@ -286,39 +284,39 @@ export function trimEnd (str: string): string { return str.slice(0, firstWS); } -function modifyFirstChar (f: (c: string) => string, s: string): string { +function modifyFirstChar(f: (c: string) => string, s: string): string { if (s === "") return s; return f(s[0]) + s.slice(1); } -export function capitalize (str: string): string { +export function capitalize(str: string): string { return modifyFirstChar(c => c.toUpperCase(), str); } -export function decapitalize (str: string): string { +export function decapitalize(str: string): string { return modifyFirstChar(c => c.toLowerCase(), str); } const wordSeparatorRegex = /[-_. ]+/; -export function pascalCase (str: string): string { +export function pascalCase(str: string): string { const words = str.split(wordSeparatorRegex).map(capitalize); return words.join(""); } -export function camelCase (str: string): string { +export function camelCase(str: string): string { return decapitalize(pascalCase(str)); } -export function snakeCase (str: string): string { +export function snakeCase(str: string): string { const words = splitIntoWords(str).map(({ word }) => word.toLowerCase()); return words.join("_"); } -export function startWithLetter ( +export function startWithLetter( isAllowedStart: (codePoint: number) => boolean, // FIXME: technically, this operates on UTF16 units upper: boolean, - str: string, + str: string ): string { const modify = upper ? capitalize : decapitalize; if (str === "") return modify("empty"); @@ -340,7 +338,7 @@ export const fastIsUpperCase = precomputedCodePointPredicate(cp => unicode.isUpp const fastNonLetter = precomputedCodePointPredicate(cp => !unicode.isLowerCase(cp) && !unicode.isUpperCase(cp)); const fastIsDigit = precomputedCodePointPredicate(isDigit); -export function splitIntoWords (s: string): WordInName[] { +export function splitIntoWords(s: string): WordInName[] { // [start, end, allUpper] const intervals: Array<[number, number, boolean]> = []; let intervalStart: number | undefined = undefined; @@ -348,15 +346,15 @@ export function splitIntoWords (s: string): WordInName[] { let i = 0; let lastLowerCaseIndex: number | undefined = undefined; - function atEnd (): boolean { + function atEnd(): boolean { return i >= len; } - function currentCodePoint (): number { + function currentCodePoint(): number { return defined(s.codePointAt(i)); } - function skipWhile (p: (codePoint: number) => boolean): void { + function skipWhile(p: (codePoint: number) => boolean): void { while (!atEnd()) { const cp = currentCodePoint(); if (!p(cp)) break; @@ -365,32 +363,32 @@ export function splitIntoWords (s: string): WordInName[] { } } - function skipNonWord (): void { + function skipNonWord(): void { skipWhile(fastIsNonWordCharacter); } - function skipLowerCase (): void { + function skipLowerCase(): void { skipWhile(fastIsLowerCase); } - function skipUpperCase (): void { + function skipUpperCase(): void { skipWhile(fastIsUpperCase); } - function skipNonLetter (): void { + function skipNonLetter(): void { skipWhile(fastNonLetter); } - function skipDigits (): void { + function skipDigits(): void { skipWhile(fastIsDigit); } - function startInterval (): void { + function startInterval(): void { assert(intervalStart === undefined, "Interval started before last one was committed"); intervalStart = i; } - function commitInterval (): void { + function commitInterval(): void { if (intervalStart === undefined) { return panic("Tried to commit interval without starting one"); } @@ -410,7 +408,7 @@ export function splitIntoWords (s: string): WordInName[] { intervalStart = undefined; } - function intervalLength (): number { + function intervalLength(): number { if (intervalStart === undefined) { return panic("Tried to get interval length without starting one"); } @@ -454,7 +452,7 @@ export function splitIntoWords (s: string): WordInName[] { const words: WordInName[] = []; for (const [start, end, allUpper] of intervals) { const word = s.slice(start, end); - const isAcronym = lastLowerCaseIndex !== undefined && allUpper || knownAcronyms.has(word.toLowerCase()); + const isAcronym = (lastLowerCaseIndex !== undefined && allUpper) || knownAcronyms.has(word.toLowerCase()); words.push({ word, isAcronym }); } @@ -463,31 +461,31 @@ export function splitIntoWords (s: string): WordInName[] { export type WordStyle = (word: string) => string; -export function firstUpperWordStyle (s: string): string { +export function firstUpperWordStyle(s: string): string { assert(s.length > 0, "Cannot style an empty string"); return s[0].toUpperCase() + s.slice(1).toLowerCase(); } -export function allUpperWordStyle (s: string): string { +export function allUpperWordStyle(s: string): string { return s.toUpperCase(); } -export function originalWord (s: string): string { +export function originalWord(s: string): string { return s; } -export function allLowerWordStyle (s: string): string { +export function allLowerWordStyle(s: string): string { return s.toLowerCase(); } -function styleWord (style: WordStyle, word: string): string { +function styleWord(style: WordStyle, word: string): string { assert(word.length > 0, "Tried to style an empty word"); const result = style(word); assert(result.length > 0, "Word style must not make word empty"); return result; } -export function combineWords ( +export function combineWords( words: WordInName[], removeInvalidCharacters: (s: string) => string, firstWordStyle: WordStyle, @@ -495,7 +493,7 @@ export function combineWords ( firstWordAcronymStyle: WordStyle, restAcronymStyle: WordStyle, separator: string, - isStartCharacter: (codePoint: number) => boolean, + isStartCharacter: (codePoint: number) => boolean ): string { const legalizedWords: WordInName[] = []; for (const w of words) { @@ -506,7 +504,7 @@ export function combineWords ( if (legalizedWords.length === 0) { const validEmpty = removeInvalidCharacters("empty"); - assert(validEmpty.length > 0, "Word \"empty\" is invalid in target language"); + assert(validEmpty.length > 0, 'Word "empty" is invalid in target language'); legalizedWords.push({ word: validEmpty, isAcronym: false }); } @@ -517,11 +515,11 @@ export function combineWords ( let restWords: WordInName[]; if (!isStartCharacter(defined(styledFirstWord.codePointAt(0)))) { const validThe = removeInvalidCharacters("the"); - assert(validThe.length > 0, "Word \"the\" is invalid in the target language"); + assert(validThe.length > 0, 'Word "the" is invalid in the target language'); const styledThe = styleWord(firstWordStyle, validThe); assert( isStartCharacter(defined(styledThe.codePointAt(0))), - "The first character of styling \"the\" is not a start character", + 'The first character of styling "the" is not a start character' ); styledWords.push(styledThe); restWords = legalizedWords; @@ -538,15 +536,15 @@ export function combineWords ( return styledWords.join(separator); } -export function addPrefixIfNecessary (prefix: string, name: string): string { +export function addPrefixIfNecessary(prefix: string, name: string): string { // Take care not to doubly-prefix type names return name.startsWith(prefix) ? name : prefix + name; } -export function makeNameStyle ( +export function makeNameStyle( namingStyle: NamingStyle, legalizeName: (name: string) => string, - prefix?: string, + prefix?: string ): (rawName: string) => string { let separator: string; let firstWordStyle: WordStyle; @@ -601,7 +599,7 @@ export function makeNameStyle ( firstWordAcronymStyle, restAcronymStyle, separator, - isLetterOrUnderscore, + isLetterOrUnderscore ); if (prefix !== undefined) { diff --git a/packages/quicktype-core/src/support/Support.ts b/packages/quicktype-core/src/support/Support.ts index ab67bbefc..0fef6624a 100644 --- a/packages/quicktype-core/src/support/Support.ts +++ b/packages/quicktype-core/src/support/Support.ts @@ -4,12 +4,12 @@ import { messageError } from "../Messages"; import * as YAML from "yaml"; export interface StringMap { - [name: string]: any; + [name: string]: any; } -export function isStringMap (x: any): x is StringMap; -export function isStringMap (x: any, checkValue: (v: any) => v is T): x is { [name: string]: T, }; -export function isStringMap (x: any, checkValue?: (v: any) => v is T): boolean { +export function isStringMap(x: any): x is StringMap; +export function isStringMap(x: any, checkValue: (v: any) => v is T): x is { [name: string]: T }; +export function isStringMap(x: any, checkValue?: (v: any) => v is T): boolean { if (typeof x !== "object" || Array.isArray(x) || x === null) { return false; } @@ -26,20 +26,20 @@ export function isStringMap (x: any, checkValue?: (v: any) => v is T): boolea return true; } -export function checkString (x: any): x is string { +export function checkString(x: any): x is string { return typeof x === "string"; } -export function checkStringMap (x: any): StringMap; -export function checkStringMap (x: any, checkValue: (v: any) => v is T): { [name: string]: T, }; -export function checkStringMap (x: any, checkValue?: (v: any) => v is T): StringMap { +export function checkStringMap(x: any): StringMap; +export function checkStringMap(x: any, checkValue: (v: any) => v is T): { [name: string]: T }; +export function checkStringMap(x: any, checkValue?: (v: any) => v is T): StringMap { if (isStringMap(x, checkValue as any)) return x; return panic(`Value must be an object, but is ${x}`); } -export function checkArray (x: any): any[]; -export function checkArray (x: any, checkItem: (v: any) => v is T): T[]; -export function checkArray (x: any, checkItem?: (v: any) => v is T): T[] { +export function checkArray(x: any): any[]; +export function checkArray(x: any, checkItem: (v: any) => v is T): T[]; +export function checkArray(x: any, checkItem?: (v: any) => v is T): T[] { if (!Array.isArray(x)) { return panic(`Value must be an array, but is ${x}`); } @@ -55,35 +55,35 @@ export function checkArray (x: any, checkItem?: (v: any) => v is T): T[] { return x; } -export function defined (x: T | undefined): T { +export function defined(x: T | undefined): T { if (x !== undefined) return x; return panic("Defined value expected, but got undefined"); } -export function nonNull (x: T | null): T { +export function nonNull(x: T | null): T { if (x !== null) return x; return panic("Non-null value expected, but got null"); } -export function assertNever (x: never): never { +export function assertNever(x: never): never { return messageError("InternalError", { message: `Unexpected object ${x as any}` }); } -export function assert (condition: boolean, message = "Assertion failed"): void { +export function assert(condition: boolean, message = "Assertion failed"): void { if (!condition) { return messageError("InternalError", { message }); } } -export function panic (message: string): never { +export function panic(message: string): never { return messageError("InternalError", { message }); } -export function mustNotHappen (): never { +export function mustNotHappen(): never { return panic("This must not happen"); } -export function repeated (n: number, value: T): T[] { +export function repeated(n: number, value: T): T[] { const arr: T[] = []; for (let i = 0; i < n; i++) { arr.push(value); @@ -92,7 +92,7 @@ export function repeated (n: number, value: T): T[] { return arr; } -export function repeatedCall (n: number, producer: () => T): T[] { +export function repeatedCall(n: number, producer: () => T): T[] { const arr: T[] = []; for (let i = 0; i < n; i++) { arr.push(producer()); @@ -101,7 +101,7 @@ export function repeatedCall (n: number, producer: () => T): T[] { return arr; } -export function errorMessage (e: any): string { +export function errorMessage(e: any): string { if (e instanceof Error) { return e.message; } @@ -109,12 +109,12 @@ export function errorMessage (e: any): string { return e.toString(); } -export function inflateBase64 (encoded: string): string { +export function inflateBase64(encoded: string): string { const bytes = Base64.atob(encoded); return pako.inflate(bytes, { to: "string" }); } -export function parseJSON (text: string, description: string, address = ""): any { +export function parseJSON(text: string, description: string, address = ""): any { try { // https://gist.github.com/pbakondy/f5045eff725193dad9c7 if (text.charCodeAt(0) === 0xfeff) { @@ -135,11 +135,11 @@ export function parseJSON (text: string, description: string, address = " nn.typeRef), + setMap(nonNulls, nn => nn.typeRef) ); } return panic("Trying to remove null results in empty union."); } -function makeScalar (builder: TypeBuilder, ft: GQLType): TypeRef { +function makeScalar(builder: TypeBuilder, ft: GQLType): TypeRef { switch (ft.name) { case "Boolean": return builder.getPrimitiveType("bool"); @@ -142,7 +142,7 @@ function makeScalar (builder: TypeBuilder, ft: GQLType): TypeRef { } } -function hasOptionalDirectives (directives?: DirectiveNode[]): boolean { +function hasOptionalDirectives(directives?: DirectiveNode[]): boolean { if (!directives) return false; for (const d of directives) { const name = d.name.value; @@ -158,7 +158,7 @@ interface Selection { selection: SelectionNode; } -function expandSelectionSet (selectionSet: SelectionSetNode, inType: GQLType, optional: boolean): Selection[] { +function expandSelectionSet(selectionSet: SelectionSetNode, inType: GQLType, optional: boolean): Selection[] { return selectionSet.selections .reverse() .map(s => ({ selection: s, inType, optional: optional || hasOptionalDirectives(s.directives) })); @@ -167,17 +167,17 @@ function expandSelectionSet (selectionSet: SelectionSetNode, inType: GQLType, op interface GQLSchema { readonly mutationType?: GQLType; readonly queryType: GQLType; - readonly types: { [name: string]: GQLType, }; + readonly types: { [name: string]: GQLType }; } class GQLQuery { private readonly _schema: GQLSchema; - private readonly _fragments: { [name: string]: FragmentDefinitionNode, }; + private readonly _fragments: { [name: string]: FragmentDefinitionNode }; - readonly queries: readonly OperationDefinitionNode[]; + public readonly queries: readonly OperationDefinitionNode[]; - constructor (schema: GQLSchema, queryString: string) { + public constructor(schema: GQLSchema, queryString: string) { this._schema = schema; this._fragments = {}; @@ -201,7 +201,7 @@ class GQLQuery { builder: TypeBuilder, fieldNode: FieldNode, fieldType: GQLType, - containingTypeName: string, + containingTypeName: string ): TypeRef => { let optional = hasOptionalDirectives(fieldNode.directives); let result: TypeRef; @@ -224,11 +224,11 @@ class GQLQuery { fieldNode.selectionSet, fieldType, fieldNode.name.value, - containingTypeName, + containingTypeName ), fieldNode.name.value, null, - containingTypeName, + containingTypeName ); case TypeKind.ENUM: if (!fieldType.enumValues) { @@ -260,7 +260,7 @@ class GQLQuery { optional = true; result = builder.getArrayType( emptyTypeAttributes, - this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName), + this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName) ); break; case TypeKind.NON_NULL: @@ -270,7 +270,7 @@ class GQLQuery { result = removeNull( builder, - this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName), + this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName) ); break; default: @@ -296,7 +296,7 @@ class GQLQuery { gqlType: GQLType, containingFieldName: string | null, containingTypeName: string | null, - overrideName?: string, + overrideName?: string ): TypeRef => { if ( gqlType.kind !== TypeKind.OBJECT && @@ -354,7 +354,7 @@ class GQLQuery { return builder.getClassType(makeNames(nameOrOverride, containingFieldName, containingTypeName), properties); }; - makeType (builder: TypeBuilder, query: OperationDefinitionNode, queryName: string): TypeRef { + public makeType(builder: TypeBuilder, query: OperationDefinitionNode, queryName: string): TypeRef { if (query.operation === "query") { return this.makeIRTypeFromSelectionSet( builder, @@ -362,7 +362,7 @@ class GQLQuery { this._schema.queryType, null, queryName, - "data", + "data" ); } @@ -377,7 +377,7 @@ class GQLQuery { this._schema.mutationType, null, queryName, - "data", + "data" ); } @@ -386,15 +386,14 @@ class GQLQuery { } class GQLSchemaFromJSON implements GQLSchema { - readonly types: { [name: string]: GQLType, } = {}; + public readonly types: { [name: string]: GQLType } = {}; // @ts-expect-error: The constructor can return early, but only by throwing. - readonly queryType: GQLType; + public readonly queryType: GQLType; - // @ts-expect-error: The constructor can return early, but only by throwing. - readonly mutationType?: GQLType; + public readonly mutationType?: GQLType; - constructor (json: any) { + public constructor(json: any) { const schema: GraphQLSchema = json.data; if (schema.__schema.queryType.name === null) { @@ -444,7 +443,7 @@ class GQLSchemaFromJSON implements GQLSchema { name: f.name, description: f.description, type: this.makeType(f.type), - args: f.args.map(this.makeInputValue), + args: f.args.map(this.makeInputValue) }; }); // console.log(`${target.name} has ${target.fields.length} fields`); @@ -478,7 +477,7 @@ class GQLSchemaFromJSON implements GQLSchema { name: iv.name, description: iv.description, type: this.makeType(iv.type), - defaultValue: iv.defaultValue, + defaultValue: iv.defaultValue }; }; @@ -493,18 +492,18 @@ class GQLSchemaFromJSON implements GQLSchema { const type: GQLType = { kind: t.kind, description: t.description, - ofType: this.makeType(t.ofType), + ofType: this.makeType(t.ofType) }; this.addTypeFields(type, t); return type; }; } -function makeGraphQLQueryTypes ( +function makeGraphQLQueryTypes( topLevelName: string, builder: TypeBuilder, json: any, - queryString: string, + queryString: string ): Map { const schema = new GQLSchemaFromJSON(json); const query = new GQLQuery(schema, queryString); @@ -518,29 +517,29 @@ function makeGraphQLQueryTypes ( const dataType = query.makeType(builder, odn, queryName); const dataOrNullType = builder.getUnionType( emptyTypeAttributes, - new Set([dataType, builder.getPrimitiveType("null")]), + new Set([dataType, builder.getPrimitiveType("null")]) ); const errorType = builder.getClassType( namesTypeAttributeKind.makeAttributes(TypeNames.make(new Set(["error"]), new Set(["graphQLError"]), false)), mapFromObject({ message: builder.makeClassProperty( builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted), - false, - ), - }), + false + ) + }) ); const errorArray = builder.getArrayType( namesTypeAttributeKind.makeAttributes( - TypeNames.make(new Set(["errors"]), new Set(["graphQLErrors"]), false), + TypeNames.make(new Set(["errors"]), new Set(["graphQLErrors"]), false) ), - errorType, + errorType ); const t = builder.getClassType( makeNamesTypeAttributes(queryName, false), mapFromObject({ data: builder.makeClassProperty(dataOrNullType, false), - errors: builder.makeClassProperty(errorArray, true), - }), + errors: builder.makeClassProperty(errorArray, true) + }) ); types.set(queryName, t); } @@ -549,42 +548,45 @@ function makeGraphQLQueryTypes ( } export interface GraphQLSourceData { - name: string; query: string; schema: any; + name: string; + query: string; + schema: any; } interface GraphQLTopLevel { - query: string; schema: any; + query: string; + schema: any; } export class GraphQLInput implements Input { - readonly kind: string = "graphql"; + public readonly kind: string = "graphql"; - readonly needIR: boolean = true; + public readonly needIR: boolean = true; - readonly needSchemaProcessing: boolean = false; + public readonly needSchemaProcessing: boolean = false; private readonly _topLevels: Map = new Map(); - async addSource (source: GraphQLSourceData): Promise { + public async addSource(source: GraphQLSourceData): Promise { this.addSourceSync(source); } - addSourceSync (source: GraphQLSourceData): void { + public addSourceSync(source: GraphQLSourceData): void { this._topLevels.set(source.name, { schema: source.schema, - query: source.query, + query: source.query }); } - singleStringSchemaSource (): undefined { + public singleStringSchemaSource(): undefined { return undefined; } - async addTypes (ctx: RunContext, typeBuilder: TypeBuilder): Promise { + public async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise { this.addTypesSync(ctx, typeBuilder); } - addTypesSync (_ctx: RunContext, typeBuilder: TypeBuilder): void { + public addTypesSync(_ctx: RunContext, typeBuilder: TypeBuilder): void { for (const [name, { schema, query }] of this._topLevels) { const newTopLevels = makeGraphQLQueryTypes(name, typeBuilder, schema, query); for (const [actualName, t] of newTopLevels) { diff --git a/src/CompressedJSONFromStream.ts b/src/CompressedJSONFromStream.ts index 850da2fc1..c442b2f8f 100644 --- a/src/CompressedJSONFromStream.ts +++ b/src/CompressedJSONFromStream.ts @@ -3,7 +3,7 @@ import { type Value } from "quicktype-core"; import { CompressedJSON } from "quicktype-core"; import { Parser } from "stream-json"; -const methodMap: { [name: string]: string, } = { +const methodMap: { [name: string]: string } = { startObject: "pushObjectContext", endObject: "finishObject", startArray: "pushArrayContext", @@ -15,13 +15,13 @@ const methodMap: { [name: string]: string, } = { stringValue: "commitString", nullValue: "commitNull", trueValue: "handleTrueValue", - falseValue: "handleFalseValue", + falseValue: "handleFalseValue" }; export class CompressedJSONFromStream extends CompressedJSON { - async parse (readStream: Readable): Promise { + public async parse(readStream: Readable): Promise { const combo = new Parser({ packKeys: true, packStrings: true }); - combo.on("data", (item: { name: string, value: string | undefined, }) => { + combo.on("data", (item: { name: string; value: string | undefined }) => { if (typeof methodMap[item.name] === "string") { (this as any)[methodMap[item.name]](item.value); } @@ -52,17 +52,17 @@ export class CompressedJSONFromStream extends CompressedJSON { } }; - protected handleEndNumber (): void { + protected handleEndNumber(): void { const isDouble = this.context.currentNumberIsDouble; this.popContext(); this.commitNumber(isDouble); } - protected handleTrueValue (): void { + protected handleTrueValue(): void { this.commitBoolean(true); } - protected handleFalseValue (): void { + protected handleFalseValue(): void { this.commitBoolean(false); } } From f79172171ad3d96faf41689d2ef60381d5ae25ee Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Thu, 11 Apr 2024 23:23:22 -0700 Subject: [PATCH 18/80] fix nullish errors --- .../quicktype-core/src/ConvenienceRenderer.ts | 2 +- .../quicktype-core/src/MakeTransformations.ts | 2 +- packages/quicktype-core/src/TypeBuilder.ts | 2 +- packages/quicktype-core/src/TypeUtils.ts | 2 +- .../src/input/JSONSchemaInput.ts | 6 +- .../src/input/io/get-stream/buffer-stream.ts | 6 +- .../src/input/io/get-stream/index.ts | 8 +- packages/quicktype-core/src/language/CJSON.ts | 428 +++++++++--------- .../src/language/Objective-C.ts | 2 +- packages/quicktype-graphql-input/src/index.ts | 2 +- src/index.ts | 219 ++++----- 11 files changed, 341 insertions(+), 338 deletions(-) diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index 7fd2041db..21e219ef0 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -743,7 +743,7 @@ export abstract class ConvenienceRenderer extends Renderer { sortOrder: ((n: Name, t: Type) => string) | null, f: (name: Name, t: Type, position: ForEachPosition) => void ): void { - const iterateMembers = members === null ? u.members : members; + const iterateMembers = members ?? u.members; if (sortOrder === null) { sortOrder = n => defined(this.names.get(n)); } diff --git a/packages/quicktype-core/src/MakeTransformations.ts b/packages/quicktype-core/src/MakeTransformations.ts index 8daede47e..0b5de7301 100644 --- a/packages/quicktype-core/src/MakeTransformations.ts +++ b/packages/quicktype-core/src/MakeTransformations.ts @@ -184,7 +184,7 @@ function replaceUnion( transformerForClass === undefined || transformerForMap === undefined, "Can't have both class and map in a transformed union" ); - const transformerForObject = transformerForClass !== undefined ? transformerForClass : transformerForMap; + const transformerForObject = transformerForClass ?? transformerForMap; const transformer = new DecodingChoiceTransformer( graph, diff --git a/packages/quicktype-core/src/TypeBuilder.ts b/packages/quicktype-core/src/TypeBuilder.ts index d9a8b17ef..5370e5be8 100644 --- a/packages/quicktype-core/src/TypeBuilder.ts +++ b/packages/quicktype-core/src/TypeBuilder.ts @@ -185,7 +185,7 @@ export class TypeBuilder { assert(this.types[typeRefIndex(forwardingRef)] === undefined); } - const tref = forwardingRef !== undefined ? forwardingRef : this.reserveTypeRef(); + const tref = forwardingRef ?? this.reserveTypeRef(); if (attributes !== undefined) { const index = typeRefIndex(tref); this.typeAttributes[index] = combineTypeAttributes("union", this.typeAttributes[index], attributes); diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index 7a39c450a..5a37546bd 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -304,7 +304,7 @@ export function matchType( typeNotSupported, enumType, unionType, - transformedStringType || typeNotSupported + transformedStringType ?? typeNotSupported ); } diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index 427e74d75..c0aa1c1b8 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -85,7 +85,7 @@ function withRef(refOrLoc: Ref | (() => Ref) | Location, props function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): any { const ref = typeof refOrLoc === "function" ? refOrLoc() : refOrLoc instanceof Ref ? refOrLoc : refOrLoc.canonicalRef; - return Object.assign({ ref }, props === undefined ? {} : props); + return Object.assign({ ref }, props ?? {}); } function checkJSONSchemaObject(x: any, refOrLoc: Ref | (() => Ref)): StringMap { @@ -378,7 +378,7 @@ class Location { public readonly haveID: boolean = false ) { this.canonicalRef = canonicalRef; - this.virtualRef = virtualRef !== undefined ? virtualRef : canonicalRef; + this.virtualRef = virtualRef ?? canonicalRef; } public updateWithID(id: any) { @@ -1143,7 +1143,7 @@ async function refsInSchemaForURI( name = schema.title; } else { const maybeName = nameFromURI(uri); - name = maybeName !== undefined ? maybeName : defaultName; + name = maybeName ?? defaultName; } return [name, ref]; diff --git a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts index f1cb10861..16ea64a20 100644 --- a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts +++ b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts @@ -1,7 +1,7 @@ import { type Options } from "."; import { PassThrough } from "readable-stream"; -export default function bufferStream (opts: Options) { +export default function bufferStream(opts: Options) { opts = Object.assign({}, opts); const array = opts.array; @@ -10,8 +10,10 @@ export default function bufferStream (opts: Options) { let objectMode = false; if (array) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing objectMode = !(encoding || buffer); } else { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing encoding = encoding || "utf8"; } @@ -22,7 +24,7 @@ export default function bufferStream (opts: Options) { let len = 0; const ret: any[] = []; const stream = new PassThrough({ - objectMode, + objectMode }) as any; if (encoding) { diff --git a/packages/quicktype-core/src/input/io/get-stream/index.ts b/packages/quicktype-core/src/input/io/get-stream/index.ts index 98ae97240..d8d067cae 100644 --- a/packages/quicktype-core/src/input/io/get-stream/index.ts +++ b/packages/quicktype-core/src/input/io/get-stream/index.ts @@ -7,14 +7,14 @@ export interface Options { maxBuffer?: number; } -export async function getStream (inputStream: Readable, opts: Options = {}) { +export async function getStream(inputStream: Readable, opts: Options = {}) { if (!inputStream) { return await Promise.reject(new Error("Expected a stream")); } opts = Object.assign({ maxBuffer: Infinity }, opts); - const maxBuffer = opts.maxBuffer || Infinity; + const maxBuffer = opts.maxBuffer ?? Infinity; let stream: any; let clean; @@ -53,10 +53,10 @@ export async function getStream (inputStream: Readable, opts: Options = {}) { return await p.then(() => stream.getBufferedValue()); } -export function buffer (stream: Readable, opts: Options = {}) { +export function buffer(stream: Readable, opts: Options = {}) { getStream(stream, Object.assign({}, opts, { encoding: "buffer" })); } -export function array (stream: Readable, opts: Options = {}) { +export function array(stream: Readable, opts: Options = {}) { getStream(stream, Object.assign({}, opts, { array: true })); } diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index 4bfb848ea..84d1c41eb 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -876,57 +876,57 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { const add = (cJSON: TypeCJSON, level: number, child_level: number) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { this.emitLine( "list_add_tail(x", child_level.toString(), ", (", - cJSON.items!.cType, + cJSON.items?.cType, " *)0xDEADBEEF, sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); - } else if (cJSON.items!.cjsonType === "cJSON_String") { + } else if (cJSON.items?.cjsonType === "cJSON_String") { this.emitLine( "list_add_tail(x", child_level.toString(), ", strdup(", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ")), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else if ( - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( "list_add_tail(x", child_level.toString(), ", ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), "), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, "));" ); this.emitBlock( @@ -936,7 +936,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ");" @@ -947,7 +947,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ", tmp", level > 0 ? level.toString() : "", ", sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } @@ -955,7 +955,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( ["if (!cJSON_IsNull(e", child_level.toString(), "))"], () => { @@ -1005,13 +1005,13 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { const add = (cJSON: TypeCJSON, level: number, child_level: number) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { this.emitLine( "hashtable_add(x", @@ -1019,28 +1019,28 @@ export class CJSONRenderer extends ConvenienceRenderer { ", e", child_level.toString(), "->string, (", - cJSON.items!.cType, + cJSON.items?.cType, " *)0xDEADBEEF, sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); - } else if (cJSON.items!.cjsonType === "cJSON_String") { + } else if (cJSON.items?.cjsonType === "cJSON_String") { this.emitLine( "hashtable_add(x", child_level.toString(), ", e", child_level.toString(), "->string, strdup(", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ")), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else if ( - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( "hashtable_add(x", @@ -1048,20 +1048,20 @@ export class CJSONRenderer extends ConvenienceRenderer { ", e", child_level.toString(), "->string, ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), "), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, "));" ); this.emitBlock( @@ -1071,7 +1071,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ");" @@ -1084,7 +1084,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "->string, tmp", level > 0 ? level.toString() : "", ", sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } @@ -1092,7 +1092,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( ["if (!cJSON_IsNull(e", child_level.toString(), "))"], () => { @@ -1185,7 +1185,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * x", child_level.toString(), " = list_get_head(x", @@ -1196,30 +1196,30 @@ export class CJSONRenderer extends ConvenienceRenderer { ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { const add = (cJSON: TypeCJSON, child_level: number) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Invalid") { + } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { /* Nothing to do */ - } else if (cJSON.items!.cjsonType === "cJSON_NULL") { + } else if (cJSON.items?.cjsonType === "cJSON_NULL") { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), ", ", - cJSON.items!.createObject, + cJSON.items?.createObject, "());" ); } else if ( - cJSON.items!.cjsonType === "cJSON_String" || - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_String" || + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), ", ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(x", child_level.toString(), "));" @@ -1229,7 +1229,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "cJSON_AddItemToArray(j", child_level.toString(), ", ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(*x", child_level.toString(), "));" @@ -1237,7 +1237,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], () => { @@ -1305,7 +1305,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " *x", child_level.toString(), " = hashtable_lookup(x", @@ -1319,13 +1319,13 @@ export class CJSONRenderer extends ConvenienceRenderer { "]);" ); const add = (cJSON: TypeCJSON, child_level: number) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Invalid") { + } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { /* Nothing to do */ - } else if (cJSON.items!.cjsonType === "cJSON_NULL") { + } else if (cJSON.items?.cjsonType === "cJSON_NULL") { this.emitLine( cJSON.addToObject, "(j", @@ -1335,13 +1335,13 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "());" ); } else if ( - cJSON.items!.cjsonType === "cJSON_String" || - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_String" || + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( cJSON.addToObject, @@ -1352,7 +1352,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(x", child_level.toString(), "));" @@ -1367,7 +1367,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(*x", child_level.toString(), "));" @@ -1375,7 +1375,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", @@ -1450,7 +1450,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * x", child_level.toString(), " = list_get_head(x", @@ -1460,22 +1460,22 @@ export class CJSONRenderer extends ConvenienceRenderer { ");" ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { /* Nothing to do */ } else { - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], () => { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -1484,7 +1484,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -1551,7 +1551,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " *x", child_level.toString(), " = hashtable_lookup(x", @@ -1565,17 +1565,17 @@ export class CJSONRenderer extends ConvenienceRenderer { "]);" ); this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { /* Nothing to do */ } else { - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", @@ -1584,7 +1584,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -1593,7 +1593,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -1766,7 +1766,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ", x", child_level2.toString(), ", sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else if (cJSON.cjsonType === "cJSON_Map") { @@ -1905,7 +1905,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level: number, child_level: number ) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { if (type instanceof ArrayType) { const child_level2 = child_level + 1; recur(type.items, child_level); @@ -1915,61 +1915,61 @@ export class CJSONRenderer extends ConvenienceRenderer { ", x", child_level2.toString(), ", sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { panic("Invalid type"); } - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { this.emitLine( "list_add_tail(x", child_level.toString(), ", (", - cJSON.items!.cType, + cJSON.items?.cType, " *)0xDEADBEEF, sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); - } else if (cJSON.items!.cjsonType === "cJSON_String") { + } else if (cJSON.items?.cjsonType === "cJSON_String") { this.emitLine( "list_add_tail(x", child_level.toString(), ", strdup(", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ")), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else if ( - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( "list_add_tail(x", child_level.toString(), ", ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), "), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, "));" ); this.emitBlock( @@ -1983,7 +1983,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ");" @@ -1994,7 +1994,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ", tmp", level > 0 ? level.toString() : "", ", sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } @@ -2002,7 +2002,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( [ "if (!cJSON_IsNull(e", @@ -2071,7 +2071,7 @@ export class CJSONRenderer extends ConvenienceRenderer { level: number, child_level: number ) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { if (type instanceof MapType) { const child_level2 = child_level + 1; recur(type.values, child_level); @@ -2083,17 +2083,17 @@ export class CJSONRenderer extends ConvenienceRenderer { "->string, x", child_level2.toString(), ", sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { panic("Invalid type"); } - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { this.emitLine( "hashtable_add(x", @@ -2101,28 +2101,28 @@ export class CJSONRenderer extends ConvenienceRenderer { ", e", child_level.toString(), "->string, (", - cJSON.items!.cType, + cJSON.items?.cType, " *)0xDEADBEEF, sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); - } else if (cJSON.items!.cjsonType === "cJSON_String") { + } else if (cJSON.items?.cjsonType === "cJSON_String") { this.emitLine( "hashtable_add(x", child_level.toString(), ", e", child_level.toString(), "->string, strdup(", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ")), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else if ( - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( "hashtable_add(x", @@ -2130,20 +2130,20 @@ export class CJSONRenderer extends ConvenienceRenderer { ", e", child_level.toString(), "->string, ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), "), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", " = cJSON_malloc(sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, "));" ); this.emitBlock( @@ -2157,7 +2157,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e", child_level.toString(), ");" @@ -2170,7 +2170,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "->string, tmp", level > 0 ? level.toString() : "", ", sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } @@ -2178,7 +2178,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( [ "if (!cJSON_IsNull(e", @@ -2478,7 +2478,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * x", child_level.toString(), " = list_get_head(x", @@ -2495,7 +2495,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON: TypeCJSON, child_level: number ) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { if (type instanceof ArrayType) { const child_level2 = child_level + 1; recur(type.items, child_level); @@ -2509,28 +2509,28 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { panic("Invalid type"); } - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Invalid") { + } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { /* Nothing to do */ - } else if (cJSON.items!.cjsonType === "cJSON_NULL") { + } else if (cJSON.items?.cjsonType === "cJSON_NULL") { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), ", ", - cJSON.items!.createObject, + cJSON.items?.createObject, "());" ); } else if ( - cJSON.items!.cjsonType === "cJSON_String" || - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_String" || + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( "cJSON_AddItemToArray(j", child_level.toString(), ", ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(x", child_level.toString(), "));" @@ -2540,7 +2540,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "cJSON_AddItemToArray(j", child_level.toString(), ", ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(*x", child_level.toString(), "));" @@ -2548,7 +2548,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", @@ -2626,7 +2626,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " *x", child_level.toString(), " = hashtable_lookup(x", @@ -2644,7 +2644,7 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON: TypeCJSON, child_level: number ) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { if (type instanceof MapType) { const child_level2 = child_level + 1; recur(type.values, child_level); @@ -2664,15 +2664,15 @@ export class CJSONRenderer extends ConvenienceRenderer { panic("Invalid type"); } } else if ( - cJSON.items!.cjsonType === "cJSON_Map" + cJSON.items?.cjsonType === "cJSON_Map" ) { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" + cJSON.items?.cjsonType === "cJSON_Invalid" ) { /* Nothing to do */ } else if ( - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_NULL" ) { this.emitLine( cJSON.addToObject, @@ -2683,13 +2683,13 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "());" ); } else if ( - cJSON.items!.cjsonType === "cJSON_String" || - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_String" || + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( cJSON.addToObject, @@ -2700,7 +2700,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(x", child_level.toString(), "));" @@ -2715,7 +2715,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(*x", child_level.toString(), "));" @@ -2723,7 +2723,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", @@ -3015,7 +3015,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " * x", child_level.toString(), " = list_get_head(x", @@ -3025,11 +3025,11 @@ export class CJSONRenderer extends ConvenienceRenderer { ");" ); this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { if (property.type instanceof ArrayType) { recur(property.type.items, child_level); this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -3037,20 +3037,20 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { panic("Invalid type"); } - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { /* Nothing to do */ } else { - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], () => { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -3059,7 +3059,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -3119,7 +3119,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " *x", child_level.toString(), " = hashtable_lookup(x", @@ -3135,11 +3135,11 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock( ["if (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { if (property.type instanceof MapType) { recur(property.type.values, child_level); this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -3147,15 +3147,15 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { panic("Invalid type"); } - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { /* Nothing to do */ } else { - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", @@ -3164,7 +3164,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -3173,7 +3173,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( - cJSON.items!.deleteType, + cJSON.items?.deleteType, "(x", child_level.toString(), ");" @@ -3350,41 +3350,41 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine("cJSON * e = NULL;"); this.emitBlock(["cJSON_ArrayForEach(e, j)"], () => { const add = (cJSON: TypeCJSON) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { this.emitLine( "list_add_tail(x->value, (", - cJSON.items!.cType, + cJSON.items?.cType, " *)0xDEADBEAF, sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); - } else if (cJSON.items!.cjsonType === "cJSON_String") { + } else if (cJSON.items?.cjsonType === "cJSON_String") { this.emitLine( "list_add_tail(x->value, strdup(", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e)), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { this.emitLine( "list_add_tail(x->value, ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock(["if (!cJSON_IsNull(e))"], () => { add(cJSON); }); @@ -3404,41 +3404,41 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine("cJSON * e = NULL;"); this.emitBlock(["cJSON_ArrayForEach(e, j)"], () => { const add = (cJSON: TypeCJSON) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ } else if ( - cJSON.items!.cjsonType === "cJSON_Invalid" || - cJSON.items!.cjsonType === "cJSON_NULL" + cJSON.items?.cjsonType === "cJSON_Invalid" || + cJSON.items?.cjsonType === "cJSON_NULL" ) { this.emitLine( "hashtable_add(x->value, e->string, (", - cJSON.items!.cType, + cJSON.items?.cType, " *)0xDEADBEEF, sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); - } else if (cJSON.items!.cjsonType === "cJSON_String") { + } else if (cJSON.items?.cjsonType === "cJSON_String") { this.emitLine( "hashtable_add(x->value, e->string, strdup(", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e)), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } else { this.emitLine( "hashtable_add(x->value, e->string, ", - cJSON.items!.getValue, + cJSON.items?.getValue, "(e), sizeof(", - cJSON.items!.cType, + cJSON.items?.cType, " *));" ); } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock(["if (!cJSON_IsNull(e))"], () => { add(cJSON); }); @@ -3479,41 +3479,41 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["if (NULL != x->value)"], () => { this.emitLine("j = ", cJSON.createObject, "();"); this.emitBlock(["if (NULL != j)"], () => { - this.emitLine(cJSON.items!.cType, " * x1 = list_get_head(x->value);"); + this.emitLine(cJSON.items?.cType, " * x1 = list_get_head(x->value);"); this.emitBlock(["while (NULL != x1)"], () => { const add = (cJSON: TypeCJSON) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Invalid") { + } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { /* Nothing to do */ - } else if (cJSON.items!.cjsonType === "cJSON_NULL") { + } else if (cJSON.items?.cjsonType === "cJSON_NULL") { this.emitLine( "cJSON_AddItemToArray(j, ", - cJSON.items!.createObject, + cJSON.items?.createObject, "());" ); } else if ( - cJSON.items!.cjsonType === "cJSON_String" || - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_String" || + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( "cJSON_AddItemToArray(j, ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(x1));" ); } else { this.emitLine( "cJSON_AddItemToArray(j, ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(*x1));" ); } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock(["if ((void *)0xDEADBEEF != x1)"], () => { add(cJSON); }); @@ -3537,45 +3537,45 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["if (NULL != keys)"], () => { this.emitBlock(["for (size_t index = 0; index < count; index++)"], () => { this.emitLine( - cJSON.items!.cType, + cJSON.items?.cType, " *x2 = hashtable_lookup(x->value, keys[index]);" ); const add = (cJSON: TypeCJSON) => { - if (cJSON.items!.cjsonType === "cJSON_Array") { + if (cJSON.items?.cjsonType === "cJSON_Array") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Map") { + } else if (cJSON.items?.cjsonType === "cJSON_Map") { /* Not supported */ - } else if (cJSON.items!.cjsonType === "cJSON_Invalid") { + } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { /* Nothing to do */ - } else if (cJSON.items!.cjsonType === "cJSON_NULL") { + } else if (cJSON.items?.cjsonType === "cJSON_NULL") { this.emitLine( cJSON.addToObject, "(j, keys[index], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "());" ); } else if ( - cJSON.items!.cjsonType === "cJSON_String" || - cJSON.items!.cjsonType === "cJSON_Object" || - cJSON.items!.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === "cJSON_String" || + cJSON.items?.cjsonType === "cJSON_Object" || + cJSON.items?.cjsonType === "cJSON_Union" ) { this.emitLine( cJSON.addToObject, "(j, keys[index], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(x2));" ); } else { this.emitLine( cJSON.addToObject, "(j, keys[index], ", - cJSON.items!.createObject, + cJSON.items?.createObject, "(*x2));" ); } }; - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock(["if ((void *)0xDEADBEEF != x2)"], () => { add(cJSON); }); @@ -3626,14 +3626,14 @@ export class CJSONRenderer extends ConvenienceRenderer { const cJSON = this.quicktypeTypeToCJSON(type, false); if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { this.emitBlock(["if (NULL != x->value)"], () => { - this.emitLine(cJSON.items!.cType, " * x1 = list_get_head(x->value);"); + this.emitLine(cJSON.items?.cType, " * x1 = list_get_head(x->value);"); this.emitBlock(["while (NULL != x1)"], () => { - if (cJSON.items!.isNullable) { + if (cJSON.items?.isNullable) { this.emitBlock(["if ((void *)0xDEADBEEF != x1)"], () => { - this.emitLine(cJSON.items!.deleteType, "(x1);"); + this.emitLine(cJSON.items?.deleteType, "(x1);"); }); } else { - this.emitLine(cJSON.items!.deleteType, "(x1);"); + this.emitLine(cJSON.items?.deleteType, "(x1);"); } this.emitLine("x1 = list_get_next(x->value);"); @@ -3646,14 +3646,14 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine("size_t count = hashtable_get_keys(x->value, &keys);"); this.emitBlock(["if (NULL != keys)"], () => { this.emitBlock(["for (size_t index = 0; index < count; index++)"], () => { - this.emitLine(cJSON.items!.cType, " *x2 = hashtable_lookup(x->value, keys[index]);"); + this.emitLine(cJSON.items?.cType, " *x2 = hashtable_lookup(x->value, keys[index]);"); this.emitBlock(["if (NULL != x2)"], () => { - if (cJSON.items!.isNullable) { - this.emitBlock(["if ((", cJSON.items!.cType, " *)0xDEADBEEF != x2)"], () => { - this.emitLine(cJSON.items!.deleteType, "(x2);"); + if (cJSON.items?.isNullable) { + this.emitBlock(["if ((", cJSON.items?.cType, " *)0xDEADBEEF != x2)"], () => { + this.emitLine(cJSON.items?.deleteType, "(x2);"); }); } else { - this.emitLine(cJSON.items!.deleteType, "(x2);"); + this.emitLine(cJSON.items?.deleteType, "(x2);"); } }); }); diff --git a/packages/quicktype-core/src/language/Objective-C.ts b/packages/quicktype-core/src/language/Objective-C.ts index e97381a00..2dc5612f1 100644 --- a/packages/quicktype-core/src/language/Objective-C.ts +++ b/packages/quicktype-core/src/language/Objective-C.ts @@ -225,7 +225,7 @@ function splitExtension(filename: string): [string, string] { const i = filename.lastIndexOf("."); const extension = i !== -1 ? filename.split(".").pop() : "m"; filename = i !== -1 ? filename.slice(0, i) : filename; - return [filename, extension === undefined ? "m" : extension]; + return [filename, extension ?? "m"]; } export class ObjectiveCRenderer extends ConvenienceRenderer { diff --git a/packages/quicktype-graphql-input/src/index.ts b/packages/quicktype-graphql-input/src/index.ts index 97bcb91ae..c2cc29cbb 100644 --- a/packages/quicktype-graphql-input/src/index.ts +++ b/packages/quicktype-graphql-input/src/index.ts @@ -310,7 +310,7 @@ class GQLQuery { return panic("Object, interface, or union type doesn't have a name."); } - const nameOrOverride = overrideName || gqlType.name; + const nameOrOverride = overrideName ?? gqlType.name; const properties = new Map(); let selections = expandSelectionSet(selectionSet, gqlType, false); for (;;) { diff --git a/src/index.ts b/src/index.ts index 710b5cc9e..78c22b445 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,7 +12,8 @@ import { type SerializedRenderResult, type TargetLanguage, type OptionDefinition, - type JSONSourceData} from "quicktype-core"; + type JSONSourceData +} from "quicktype-core"; import { getTargetLanguage, quicktypeMultiFile, @@ -38,7 +39,7 @@ import { getStream, readableFromFileOrURL, readFromFileOrURL, - FetchingJSONSchemaStore, + FetchingJSONSchemaStore } from "quicktype-core"; import { schemaForTypeScriptSources } from "quicktype-typescript-input"; import { GraphQLInput } from "quicktype-graphql-input"; @@ -89,22 +90,22 @@ export interface CLIOptions { const defaultDefaultTargetLanguageName = "go"; -async function sourceFromFileOrUrlArray ( +async function sourceFromFileOrUrlArray( name: string, filesOrUrls: string[], - httpHeaders?: string[], + httpHeaders?: string[] ): Promise { const samples = await Promise.all(filesOrUrls.map(async file => await readableFromFileOrURL(file, httpHeaders))); return { kind: "json", name, samples }; } -function typeNameFromFilename (filename: string): string { +function typeNameFromFilename(filename: string): string { const name = path.basename(filename); return name.substring(0, name.lastIndexOf(".")); } -async function samplesFromDirectory (dataDir: string, httpHeaders?: string[]): Promise { - async function readFilesOrURLsInDirectory (d: string): Promise { +async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Promise { + async function readFilesOrURLsInDirectory(d: string): Promise { const files = fs .readdirSync(d) .map(x => path.join(d, x)) @@ -129,17 +130,17 @@ async function samplesFromDirectory (dataDir: string, httpHeaders?: string[]): P sourcesInDir.push({ kind: "json", name, - samples: [await readableFromFileOrURL(fileOrUrl, httpHeaders)], + samples: [await readableFromFileOrURL(fileOrUrl, httpHeaders)] }); } else if (file.endsWith(".schema")) { sourcesInDir.push({ kind: "schema", name, - uris: [fileOrUrl], + uris: [fileOrUrl] }); } else if (file.endsWith(".gqlschema")) { messageAssert(graphQLSchema === undefined, "DriverMoreThanOneGraphQLSchemaInDir", { - dir: dataDir, + dir: dataDir }); graphQLSchema = await readableFromFileOrURL(fileOrUrl, httpHeaders); graphQLSchemaFileName = fileOrUrl; @@ -148,7 +149,7 @@ async function samplesFromDirectory (dataDir: string, httpHeaders?: string[]): P kind: "graphql", name, schema: undefined, - query: await getStream(await readableFromFileOrURL(fileOrUrl, httpHeaders)), + query: await getStream(await readableFromFileOrURL(fileOrUrl, httpHeaders)) }); } } @@ -207,7 +208,7 @@ async function samplesFromDirectory (dataDir: string, httpHeaders?: string[]): P sources.push({ kind: "json", name: path.basename(dir), - samples: jsonSamples, + samples: jsonSamples }); } @@ -218,7 +219,7 @@ async function samplesFromDirectory (dataDir: string, httpHeaders?: string[]): P return sources; } -function inferLang (options: Partial, defaultLanguage: string): string { +function inferLang(options: Partial, defaultLanguage: string): string { // Output file extension determines the language if language is undefined if (options.out !== undefined) { let extension = path.extname(options.out); @@ -232,7 +233,7 @@ function inferLang (options: Partial, defaultLanguage: string): stri return defaultLanguage; } -function inferTopLevel (options: Partial): string { +function inferTopLevel(options: Partial): string { // Output file name determines the top-level if undefined if (options.out !== undefined) { let extension = path.extname(options.out); @@ -251,7 +252,7 @@ function inferTopLevel (options: Partial): string { return "TopLevel"; } -function inferCLIOptions (opts: Partial, targetLanguage: TargetLanguage | undefined): CLIOptions { +function inferCLIOptions(opts: Partial, targetLanguage: TargetLanguage | undefined): CLIOptions { let srcLang = opts.srcLang; if (opts.graphqlSchema !== undefined || opts.graphqlIntrospect !== undefined) { messageAssert(srcLang === undefined || srcLang === "graphql", "DriverSourceLangMustBeGraphQL", {}); @@ -267,7 +268,7 @@ function inferCLIOptions (opts: Partial, targetLanguage: TargetLangu if (targetLanguage !== undefined) { language = targetLanguage; } else { - const languageName = opts.lang !== undefined ? opts.lang : inferLang(opts, defaultDefaultTargetLanguageName); + const languageName = opts.lang ?? inferLang(opts, defaultDefaultTargetLanguageName); const maybeLanguage = languageNamed(languageName); if (maybeLanguage === undefined) { return messageError("DriverUnknownOutputLanguage", { lang: languageName }); @@ -277,27 +278,27 @@ function inferCLIOptions (opts: Partial, targetLanguage: TargetLangu } const options: CLIOptions = { - src: opts.src || [], + src: opts.src ?? [], srcUrls: opts.srcUrls, srcLang: srcLang, lang: language.displayName, - topLevel: opts.topLevel || inferTopLevel(opts), + topLevel: opts.topLevel ?? inferTopLevel(opts), noRender: !!opts.noRender, alphabetizeProperties: !!opts.alphabetizeProperties, allPropertiesOptional: !!opts.allPropertiesOptional, - rendererOptions: opts.rendererOptions || {}, - help: opts.help || false, - quiet: opts.quiet || false, - version: opts.version || false, + rendererOptions: opts.rendererOptions ?? {}, + help: opts.help ?? false, + quiet: opts.quiet ?? false, + version: opts.version ?? false, out: opts.out, buildMarkovChain: opts.buildMarkovChain, - additionalSchema: opts.additionalSchema || [], + additionalSchema: opts.additionalSchema ?? [], graphqlSchema: opts.graphqlSchema, graphqlIntrospect: opts.graphqlIntrospect, httpMethod: opts.httpMethod, httpHeader: opts.httpHeader, debug: opts.debug, - telemetry: opts.telemetry, + telemetry: opts.telemetry }; for (const flagName of inferenceFlagNames) { const cliName = negatedInferenceFlagName(flagName); @@ -307,12 +308,12 @@ function inferCLIOptions (opts: Partial, targetLanguage: TargetLangu return options; } -function makeLangTypeLabel (targetLanguages: TargetLanguage[]): string { +function makeLangTypeLabel(targetLanguages: TargetLanguage[]): string { assert(targetLanguages.length > 0, "Must have at least one target language"); return targetLanguages.map(r => _.minBy(r.names, s => s.length)).join("|"); } -function negatedInferenceFlagName (name: string): string { +function negatedInferenceFlagName(name: string): string { const prefix = "infer"; if (name.startsWith(prefix)) { name = name.slice(prefix.length); @@ -321,41 +322,41 @@ function negatedInferenceFlagName (name: string): string { return "no" + capitalize(name); } -function dashedFromCamelCase (name: string): string { +function dashedFromCamelCase(name: string): string { return splitIntoWords(name) .map(w => w.word.toLowerCase()) .join("-"); } -function makeOptionDefinitions (targetLanguages: TargetLanguage[]): OptionDefinition[] { +function makeOptionDefinitions(targetLanguages: TargetLanguage[]): OptionDefinition[] { const beforeLang: OptionDefinition[] = [ { name: "out", alias: "o", type: String, typeLabel: "FILE", - description: "The output file. Determines --lang and --top-level.", + description: "The output file. Determines --lang and --top-level." }, { name: "top-level", alias: "t", type: String, typeLabel: "NAME", - description: "The name for the top level type.", - }, + description: "The name for the top level type." + } ]; const lang: OptionDefinition[] = targetLanguages.length < 2 ? [] : [ - { - name: "lang", - alias: "l", - type: String, - typeLabel: "LANG", - description: "The target language.", - }, - ]; + { + name: "lang", + alias: "l", + type: String, + typeLabel: "LANG", + description: "The target language." + } + ]; const afterLang: OptionDefinition[] = [ { name: "src-lang", @@ -363,7 +364,7 @@ function makeOptionDefinitions (targetLanguages: TargetLanguage[]): OptionDefini type: String, defaultValue: undefined, typeLabel: "SRC_LANG", - description: "The source language (default is json).", + description: "The source language (default is json)." }, { name: "src", @@ -371,49 +372,49 @@ function makeOptionDefinitions (targetLanguages: TargetLanguage[]): OptionDefini multiple: true, defaultOption: true, typeLabel: "FILE|URL|DIRECTORY", - description: "The file, url, or data directory to type.", + description: "The file, url, or data directory to type." }, { name: "src-urls", type: String, typeLabel: "FILE", - description: "Tracery grammar describing URLs to crawl.", - }, + description: "Tracery grammar describing URLs to crawl." + } ]; const inference: OptionDefinition[] = Array.from( mapMap(mapFromObject(inferenceFlags), (flag, name) => { return { name: dashedFromCamelCase(negatedInferenceFlagName(name)), type: Boolean, - description: flag.negationDescription + ".", + description: flag.negationDescription + "." }; - }).values(), + }).values() ); const afterInference: OptionDefinition[] = [ { name: "graphql-schema", type: String, typeLabel: "FILE", - description: "GraphQL introspection file.", + description: "GraphQL introspection file." }, { name: "graphql-introspect", type: String, typeLabel: "URL", - description: "Introspect GraphQL schema from a server.", + description: "Introspect GraphQL schema from a server." }, { name: "http-method", type: String, typeLabel: "METHOD", - description: "HTTP method to use for the GraphQL introspection query.", + description: "HTTP method to use for the GraphQL introspection query." }, { name: "http-header", type: String, multiple: true, typeLabel: "HEADER", - description: "Header(s) to attach to all HTTP requests, including the GraphQL introspection query.", + description: "Header(s) to attach to all HTTP requests, including the GraphQL introspection query." }, { name: "additional-schema", @@ -421,66 +422,66 @@ function makeOptionDefinitions (targetLanguages: TargetLanguage[]): OptionDefini type: String, multiple: true, typeLabel: "FILE", - description: "Register the $id's of additional JSON Schema files.", + description: "Register the $id's of additional JSON Schema files." }, { name: "no-render", type: Boolean, - description: "Don't render output.", + description: "Don't render output." }, { name: "alphabetize-properties", type: Boolean, - description: "Alphabetize order of class properties.", + description: "Alphabetize order of class properties." }, { name: "all-properties-optional", type: Boolean, - description: "Make all class properties optional.", + description: "Make all class properties optional." }, { name: "build-markov-chain", type: String, typeLabel: "FILE", - description: "Markov chain corpus filename.", + description: "Markov chain corpus filename." }, { name: "quiet", type: Boolean, - description: "Don't show issues in the generated code.", + description: "Don't show issues in the generated code." }, { name: "debug", type: String, typeLabel: "OPTIONS or all", description: - "Comma separated debug options: print-graph, print-reconstitution, print-gather-names, print-transformations, print-schema-resolving, print-times, provenance", + "Comma separated debug options: print-graph, print-reconstitution, print-gather-names, print-transformations, print-schema-resolving, print-times, provenance" }, { name: "telemetry", type: String, typeLabel: "enable|disable", - description: "Enable anonymous telemetry to help improve quicktype", + description: "Enable anonymous telemetry to help improve quicktype" }, { name: "help", alias: "h", type: Boolean, - description: "Get some help.", + description: "Get some help." }, { name: "version", alias: "v", type: Boolean, - description: "Display the version of quicktype", - }, + description: "Display the version of quicktype" + } ]; return beforeLang.concat(lang, afterLang, inference, afterInference); } interface ColumnDefinition { name: string; - padding?: { left: string, right: string, }; + padding?: { left: string; right: string }; width?: number; } @@ -500,16 +501,16 @@ const tableOptionsForOptions: TableOptions = { columns: [ { name: "option", - width: 60, + width: 60 }, { name: "description", - width: 60, - }, - ], + width: 60 + } + ] }; -function makeSectionsBeforeRenderers (targetLanguages: TargetLanguage[]): UsageSection[] { +function makeSectionsBeforeRenderers(targetLanguages: TargetLanguage[]): UsageSection[] { const langDisplayNames = targetLanguages.map(r => r.displayName).join(", "); return [ @@ -517,24 +518,24 @@ function makeSectionsBeforeRenderers (targetLanguages: TargetLanguage[]): UsageS header: "Synopsis", content: [ `$ quicktype [${chalk.bold("--lang")} LANG] [${chalk.bold("--src-lang")} SRC_LANG] [${chalk.bold( - "--out", + "--out" )} FILE] FILE|URL ...`, "", ` LANG ... ${makeLangTypeLabel(targetLanguages)}`, "", - "SRC_LANG ... json|schema|graphql|postman|typescript", - ], + "SRC_LANG ... json|schema|graphql|postman|typescript" + ] }, { header: "Description", - content: `Given JSON sample data, quicktype outputs code for working with that data in ${langDisplayNames}.`, + content: `Given JSON sample data, quicktype outputs code for working with that data in ${langDisplayNames}.` }, { header: "Options", optionList: makeOptionDefinitions(targetLanguages), hide: ["no-render", "build-markov-chain"], - tableOptions: tableOptionsForOptions, - }, + tableOptions: tableOptionsForOptions + } ]; } @@ -551,21 +552,21 @@ const sectionsAfterRenderers: UsageSection[] = [ + Bar - bar-sample-1.json - bar-sample-2.json - - Baz.url`, + - Baz.url` ), "$ quicktype -l go samples", "", chalk.dim("Generate JSON Schema, then TypeScript"), "$ quicktype -o schema.json https://blockchain.info/latestblock", - "$ quicktype -o bitcoin.ts --src-lang schema schema.json", - ], + "$ quicktype -o bitcoin.ts --src-lang schema schema.json" + ] }, { - content: `Learn more at ${chalk.bold("quicktype.io")}`, - }, + content: `Learn more at ${chalk.bold("quicktype.io")}` + } ]; -export function parseCLIOptions (argv: string[], targetLanguage?: TargetLanguage): CLIOptions { +export function parseCLIOptions(argv: string[], targetLanguage?: TargetLanguage): CLIOptions { if (argv.length === 0) { return inferCLIOptions({ help: true }, targetLanguage); } @@ -592,8 +593,8 @@ export function parseCLIOptions (argv: string[], targetLanguage?: TargetLanguage // Parse the options in argv and split them into global options and renderer options, // according to each option definition's `renderer` field. If `partial` is false this // will throw if it encounters an unknown option. -function parseOptions (definitions: OptionDefinition[], argv: string[], partial: boolean): Partial { - let opts: { [key: string]: any, }; +function parseOptions(definitions: OptionDefinition[], argv: string[], partial: boolean): Partial { + let opts: { [key: string]: any }; try { opts = commandLineArgs(definitions, { argv, partial }); } catch (e) { @@ -604,12 +605,12 @@ function parseOptions (definitions: OptionDefinition[], argv: string[], partial: for (const k of Object.keys(opts)) { if (opts[k] === null) { return messageError("DriverCLIOptionParsingFailed", { - message: `Missing value for command line option "${k}"`, + message: `Missing value for command line option "${k}"` }); } } - const options: { [key: string]: any, rendererOptions: RendererOptions, } = { rendererOptions: {} }; + const options: { [key: string]: any; rendererOptions: RendererOptions } = { rendererOptions: {} }; for (const o of definitions) { if (!hasOwnProperty(opts, o.name)) continue; const v = opts[o.name] as string; @@ -623,7 +624,7 @@ function parseOptions (definitions: OptionDefinition[], argv: string[], partial: return options; } -function usage (targetLanguages: TargetLanguage[]) { +function usage(targetLanguages: TargetLanguage[]) { const rendererSections: UsageSection[] = []; for (const language of targetLanguages) { @@ -633,7 +634,7 @@ function usage (targetLanguages: TargetLanguage[]) { rendererSections.push({ header: `Options for ${language.displayName}`, optionList: definitions, - tableOptions: tableOptionsForOptions, + tableOptions: tableOptionsForOptions }); } @@ -643,12 +644,12 @@ function usage (targetLanguages: TargetLanguage[]) { } // Returns an array of [name, sourceURIs] pairs. -async function getSourceURIs (options: CLIOptions): Promise> { +async function getSourceURIs(options: CLIOptions): Promise> { if (options.srcUrls !== undefined) { const json = parseJSON( await readFromFileOrURL(options.srcUrls, options.httpHeader), "URL grammar", - options.srcUrls, + options.srcUrls ); const jsonMap = urlsFromURLGrammar(json); const topLevels = Object.getOwnPropertyNames(jsonMap); @@ -660,7 +661,7 @@ async function getSourceURIs (options: CLIOptions): Promise { +async function typeSourcesForURIs(name: string, uris: string[], options: CLIOptions): Promise { switch (options.srcLang) { case "json": return [await sourceFromFileOrUrlArray(name, uris, options.httpHeader)]; @@ -671,10 +672,10 @@ async function typeSourcesForURIs (name: string, uris: string[], options: CLIOpt } } -async function getSources (options: CLIOptions): Promise { +async function getSources(options: CLIOptions): Promise { const sourceURIs = await getSourceURIs(options); const sourceArrays = await Promise.all( - sourceURIs.map(async ([name, uris]) => await typeSourcesForURIs(name, uris, options)), + sourceURIs.map(async ([name, uris]) => await typeSourcesForURIs(name, uris, options)) ); let sources: TypeSource[] = ([] as TypeSource[]).concat(...sourceArrays); @@ -688,20 +689,20 @@ async function getSources (options: CLIOptions): Promise { // Every src that's not a directory is assumed to be a file or URL const filesOrUrls = options.src.filter(x => !_.includes(directories, x)); if (!_.isEmpty(filesOrUrls)) { - sources.push(...await typeSourcesForURIs(options.topLevel, filesOrUrls, options)); + sources.push(...(await typeSourcesForURIs(options.topLevel, filesOrUrls, options))); } return sources; } -function makeTypeScriptSource (fileNames: string[]): SchemaTypeSource { +function makeTypeScriptSource(fileNames: string[]): SchemaTypeSource { return Object.assign({ kind: "schema" }, schemaForTypeScriptSources(fileNames)) as SchemaTypeSource; } -export function jsonInputForTargetLanguage ( +export function jsonInputForTargetLanguage( targetLanguage: string | TargetLanguage, languages?: TargetLanguage[], - handleJSONRefs = false, + handleJSONRefs = false ): JSONInput { if (typeof targetLanguage === "string") { targetLanguage = defined(languageNamed(targetLanguage, languages)); @@ -711,12 +712,12 @@ export function jsonInputForTargetLanguage ( return new JSONInput(compressedJSON); } -async function makeInputData ( +async function makeInputData( sources: TypeSource[], targetLanguage: TargetLanguage, additionalSchemaAddresses: readonly string[], handleJSONRefs: boolean, - httpHeaders?: string[], + httpHeaders?: string[] ): Promise { const inputData = new InputData(); @@ -727,14 +728,14 @@ async function makeInputData ( break; case "json": await inputData.addSource("json", source, () => - jsonInputForTargetLanguage(targetLanguage, undefined, handleJSONRefs), + jsonInputForTargetLanguage(targetLanguage, undefined, handleJSONRefs) ); break; case "schema": await inputData.addSource( "schema", source, - () => new JSONSchemaInput(new FetchingJSONSchemaStore(httpHeaders), [], additionalSchemaAddresses), + () => new JSONSchemaInput(new FetchingJSONSchemaStore(httpHeaders), [], additionalSchemaAddresses) ); break; default: @@ -745,16 +746,16 @@ async function makeInputData ( return inputData; } -function stringSourceDataToStreamSourceData (src: JSONSourceData): JSONSourceData { +function stringSourceDataToStreamSourceData(src: JSONSourceData): JSONSourceData { return { name: src.name, description: src.description, samples: src.samples.map(stringToStream) }; } -export async function makeQuicktypeOptions ( +export async function makeQuicktypeOptions( options: CLIOptions, - targetLanguages?: TargetLanguage[], + targetLanguages?: TargetLanguage[] ): Promise | undefined> { if (options.help) { - usage(targetLanguages === undefined ? defaultTargetLanguages : targetLanguages); + usage(targetLanguages ?? defaultTargetLanguages); return undefined; } @@ -783,7 +784,7 @@ export async function makeQuicktypeOptions ( schemaString = await introspectServer( options.graphqlIntrospect, withDefault(options.httpMethod, "POST"), - withDefault(options.httpHeader, []), + withDefault(options.httpHeader, []) ); if (options.graphqlSchema !== undefined) { fs.writeFileSync(options.graphqlSchema, schemaString); @@ -836,11 +837,11 @@ export async function makeQuicktypeOptions ( const collectionJSON = fs.readFileSync(collectionFile, "utf8"); const { sources: postmanSources, description } = sourcesFromPostmanCollection( collectionJSON, - collectionFile, + collectionFile ); for (const src of postmanSources) { sources.push( - Object.assign({ kind: "json" }, stringSourceDataToStreamSourceData(src)) as JSONTypeSource, + Object.assign({ kind: "json" }, stringSourceDataToStreamSourceData(src)) as JSONTypeSource ); } @@ -910,7 +911,7 @@ export async function makeQuicktypeOptions ( debugPrintGatherNames, debugPrintTransformations, debugPrintSchemaResolving, - debugPrintTimes, + debugPrintTimes }; for (const flagName of inferenceFlagNames) { const cliName = negatedInferenceFlagName(flagName); @@ -927,15 +928,15 @@ export async function makeQuicktypeOptions ( lang, options.additionalSchema, quicktypeOptions.ignoreJsonRefs !== true, - options.httpHeader, + options.httpHeader ); return quicktypeOptions; } -export function writeOutput ( +export function writeOutput( cliOptions: CLIOptions, - resultsByFilename: ReadonlyMap, + resultsByFilename: ReadonlyMap ): void { let onFirst = true; for (const [filename, { lines, annotations }] of resultsByFilename) { @@ -972,7 +973,7 @@ export function writeOutput ( } } -export async function main (args: string[] | Partial) { +export async function main(args: string[] | Partial) { let cliOptions: CLIOptions; if (Array.isArray(args)) { cliOptions = parseCLIOptions(args); From db9a9cfa620e86fd002bc6f4929a2d2a5ef8fa3a Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 00:05:51 -0700 Subject: [PATCH 19/80] update import rules --- .eslintrc.json | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index fcf73b84b..c14276ec1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,8 @@ "eslint:recommended", "canonical/typescript", "canonical/typescript-type-checking", - "plugin:import/recommended", + "plugin:import/errors", + "plugin:import/warnings", "plugin:import/typescript" ], "plugins": ["canonical"], @@ -28,6 +29,41 @@ "no-extra-parens": "off", "canonical/prefer-inline-type-import": "error", "typescript-sort-keys/string-enum": "off", + + "sort-imports": [ + "error", + { + "ignoreDeclarationSort": true + } + ], + "no-duplicate-imports": "error", + "import/first": "error", + "import/order": [ + "error", + { + "newlines-between": "always", + "groups": ["builtin", "external", "internal", "parent", "sibling", "index", "object", "type"], + "pathGroups": [ + { + "pattern": "@/**", + "group": "internal", + "position": "before" + } + ], + "alphabetize": { + "order": "asc" /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */, + "caseInsensitive": true /* ignore case. Options: [true, false] */ + } + } + ], + + "import/no-absolute-path": "error", + "import/no-cycle": "error", + "import/no-duplicates": "error", + "import/no-extraneous-dependencies": "error", + "import/no-named-as-default": "off", + "import/no-useless-path-segments": "error", + "@typescript-eslint/class-literal-property-style": "off", "@typescript-eslint/comma-dangle": "off", "@typescript-eslint/consistent-type-definitions": ["error", "interface"], From 3088be7d251b6cdaed39f934140d77ec3f64cf25 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 07:42:43 -0700 Subject: [PATCH 20/80] fix all require imports --- package-lock.json | 31 ++++++++++++++++++- package.json | 1 + packages/quicktype-core/package.json | 4 ++- .../quicktype-core/src/ConvenienceRenderer.ts | 3 +- .../quicktype-core/src/input/io/NodeIO.ts | 10 +++--- src/index.ts | 8 +++-- tsconfig.json | 3 +- 7 files changed, 48 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6bcb1cc29..566209a26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "@types/shelljs": "^0.8.12", "@types/stream-json": "^1.7.3", "@types/urijs": "^1.19.25", + "@types/wordwrap": "^1.0.3", "@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/parser": "^6.3.0", "ajv": "^5.5.2", @@ -51,7 +52,7 @@ "eslint": "^8.57.0", "eslint-config-canonical": "^41.1.7", "eslint-config-prettier": "^6.10.0", - "eslint-import-resolver-typescript": "^3.5.2", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-canonical": "^3.4.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-json": "^3.1.0", @@ -1230,6 +1231,12 @@ "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", "dev": true }, + "node_modules/@types/is-url": { + "version": "1.2.32", + "resolved": "https://registry.npmjs.org/@types/is-url/-/is-url-1.2.32.tgz", + "integrity": "sha512-46VLdbWI8Sc+hPexQ6NLNR2YpoDyDZIpASHkJQ2Yr+Kf9Giw6LdCTkwOdsnHKPQeh7xTjTmSnxbE8qpxYuCiHA==", + "dev": true + }, "node_modules/@types/js-base64": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/@types/js-base64/-/js-base64-3.3.1.tgz", @@ -1342,6 +1349,12 @@ "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==" }, + "node_modules/@types/wordwrap": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/wordwrap/-/wordwrap-1.0.3.tgz", + "integrity": "sha512-jx39cOYWJxZxVOZeNHvLVoDLRUFcYtIJaurC6C0qzCovIB3GPDbMDbYvoWi9D1B2PtIE16rElQOFR4Y+8QbUgw==", + "dev": true + }, "node_modules/@types/ws": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", @@ -8815,12 +8828,14 @@ }, "devDependencies": { "@types/browser-or-node": "^1.3.2", + "@types/is-url": "^1.2.32", "@types/js-base64": "^3.3.1", "@types/node": "18.14.0", "@types/pako": "^1.0.0", "@types/pluralize": "0.0.30", "@types/readable-stream": "4.0.10", "@types/unicode-properties": "^1.3.0", + "@types/wordwrap": "^1.0.3", "@types/yaml": "^1.9.7", "typescript": "4.9.5" } @@ -9868,6 +9883,12 @@ "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", "dev": true }, + "@types/is-url": { + "version": "1.2.32", + "resolved": "https://registry.npmjs.org/@types/is-url/-/is-url-1.2.32.tgz", + "integrity": "sha512-46VLdbWI8Sc+hPexQ6NLNR2YpoDyDZIpASHkJQ2Yr+Kf9Giw6LdCTkwOdsnHKPQeh7xTjTmSnxbE8qpxYuCiHA==", + "dev": true + }, "@types/js-base64": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/@types/js-base64/-/js-base64-3.3.1.tgz", @@ -9979,6 +10000,12 @@ "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==" }, + "@types/wordwrap": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/wordwrap/-/wordwrap-1.0.3.tgz", + "integrity": "sha512-jx39cOYWJxZxVOZeNHvLVoDLRUFcYtIJaurC6C0qzCovIB3GPDbMDbYvoWi9D1B2PtIE16rElQOFR4Y+8QbUgw==", + "dev": true + }, "@types/ws": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", @@ -14066,6 +14093,7 @@ "requires": { "@glideapps/ts-necessities": "2.1.3", "@types/browser-or-node": "^1.3.2", + "@types/is-url": "^1.2.32", "@types/js-base64": "^3.3.1", "@types/node": "18.14.0", "@types/pako": "^1.0.0", @@ -14073,6 +14101,7 @@ "@types/readable-stream": "4.0.10", "@types/unicode-properties": "^1.3.0", "@types/urijs": "^1.19.25", + "@types/wordwrap": "^1.0.3", "@types/yaml": "^1.9.7", "browser-or-node": "^2.1.1", "collection-utils": "^1.0.1", diff --git a/package.json b/package.json index 17ee5b728..24d02f243 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "@types/shelljs": "^0.8.12", "@types/stream-json": "^1.7.3", "@types/urijs": "^1.19.25", + "@types/wordwrap": "^1.0.3", "@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/parser": "^6.3.0", "ajv": "^5.5.2", diff --git a/packages/quicktype-core/package.json b/packages/quicktype-core/package.json index 0cbd4a35b..7adb7bc4b 100644 --- a/packages/quicktype-core/package.json +++ b/packages/quicktype-core/package.json @@ -15,8 +15,8 @@ "@types/urijs": "^1.19.25", "browser-or-node": "^2.1.1", "collection-utils": "^1.0.1", - "is-url": "^1.2.4", "cross-fetch": "^4.0.0", + "is-url": "^1.2.4", "js-base64": "^3.7.5", "lodash": "^4.17.21", "pako": "^1.0.6", @@ -29,12 +29,14 @@ }, "devDependencies": { "@types/browser-or-node": "^1.3.2", + "@types/is-url": "^1.2.32", "@types/js-base64": "^3.3.1", "@types/node": "18.14.0", "@types/pako": "^1.0.0", "@types/pluralize": "0.0.30", "@types/readable-stream": "4.0.10", "@types/unicode-properties": "^1.3.0", + "@types/wordwrap": "^1.0.3", "@types/yaml": "^1.9.7", "typescript": "4.9.5" }, diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index 21e219ef0..bcb6a9304 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -32,7 +32,8 @@ import { transformationForType, followTargetType } from "./Transformers"; import { type TargetLanguage } from "./TargetLanguage"; import { type Comment, isStringComment, type CommentOptions } from "./support/Comments"; -const wordWrap: (s: string) => string = require("wordwrap")(90); +import _wordwrap from "wordwrap"; +const wordWrap: (s: string) => string = _wordwrap(90); export const topLevelNameOrder = 1; diff --git a/packages/quicktype-core/src/input/io/NodeIO.ts b/packages/quicktype-core/src/input/io/NodeIO.ts index bb6d3f8f9..fdc63b6b5 100644 --- a/packages/quicktype-core/src/input/io/NodeIO.ts +++ b/packages/quicktype-core/src/input/io/NodeIO.ts @@ -5,14 +5,14 @@ import { getStream } from "./get-stream"; import { defined, exceptionToString } from "@glideapps/ts-necessities"; import { messageError, panic } from "../../index"; -const isURL = require("is-url"); +import isURL from "is-url"; import fetch from "cross-fetch"; interface HttpHeaders { [key: string]: string; } -function parseHeaders (httpHeaders?: string[]): HttpHeaders { +function parseHeaders(httpHeaders?: string[]): HttpHeaders { if (!Array.isArray(httpHeaders)) { return {}; } @@ -34,11 +34,11 @@ function parseHeaders (httpHeaders?: string[]): HttpHeaders { }, {} as HttpHeaders); } -export async function readableFromFileOrURL (fileOrURL: string, httpHeaders?: string[]): Promise { +export async function readableFromFileOrURL(fileOrURL: string, httpHeaders?: string[]): Promise { try { if (isURL(fileOrURL)) { const response = await fetch(fileOrURL, { - headers: parseHeaders(httpHeaders), + headers: parseHeaders(httpHeaders) }); return defined(response.body) as unknown as Readable; } else if (isNode) { @@ -60,7 +60,7 @@ export async function readableFromFileOrURL (fileOrURL: string, httpHeaders?: st return messageError("DriverInputFileDoesNotExist", { filename: fileOrURL }); } -export async function readFromFileOrURL (fileOrURL: string, httpHeaders?: string[]): Promise { +export async function readFromFileOrURL(fileOrURL: string, httpHeaders?: string[]): Promise { const readable = await readableFromFileOrURL(fileOrURL, httpHeaders); try { return await getStream(readable); diff --git a/src/index.ts b/src/index.ts index 78c22b445..a71cfe3f5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -49,14 +49,16 @@ import { introspectServer } from "./GraphQLIntrospection"; import { type JSONTypeSource, type TypeSource, type GraphQLTypeSource, type SchemaTypeSource } from "./TypeSource"; import { CompressedJSONFromStream } from "./CompressedJSONFromStream"; -const stringToStream = require("string-to-stream"); +import stringToStream from "string-to-stream"; import commandLineArgs from "command-line-args"; import getUsage from "command-line-usage"; import chalk from "chalk"; -const wordWrap: (s: string) => string = require("wordwrap")(90); -const packageJSON = require("../package.json"); +import _wordwrap from "wordwrap"; +const wordWrap: (s: string) => string = _wordwrap(90); + +import packageJSON from "../package.json"; export interface CLIOptions { // We use this to access the inference flags diff --git a/tsconfig.json b/tsconfig.json index 60bab643b..4f1446d5e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,8 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "outDir": "dist", - "baseUrl": "src" + "baseUrl": "src", + "resolveJsonModule": true }, "include": ["src"] } From c492962d34c6bb70eb6b39bb7e97441c7773b23b Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 08:25:00 -0700 Subject: [PATCH 21/80] fix all imports --- .../quicktype-core/src/ConvenienceRenderer.ts | 52 +++++------ packages/quicktype-core/src/DeclarationIR.ts | 8 +- packages/quicktype-core/src/GatherNames.ts | 11 ++- packages/quicktype-core/src/Graph.ts | 2 +- packages/quicktype-core/src/GraphRewriting.ts | 26 +++--- .../quicktype-core/src/MakeTransformations.ts | 57 ++++++------ packages/quicktype-core/src/MarkovChain.ts | 2 +- packages/quicktype-core/src/Messages.ts | 14 +-- packages/quicktype-core/src/Naming.ts | 20 ++--- packages/quicktype-core/src/Renderer.ts | 13 ++- .../quicktype-core/src/RendererOptions.ts | 6 +- packages/quicktype-core/src/Run.ts | 30 +++---- packages/quicktype-core/src/Source.ts | 2 +- packages/quicktype-core/src/TargetLanguage.ts | 18 ++-- packages/quicktype-core/src/Transformers.ts | 18 ++-- packages/quicktype-core/src/Type.ts | 40 ++++----- packages/quicktype-core/src/TypeBuilder.ts | 59 ++++++------ packages/quicktype-core/src/TypeGraph.ts | 29 +++--- packages/quicktype-core/src/TypeUtils.ts | 33 +++++-- packages/quicktype-core/src/UnifyClasses.ts | 17 ++-- packages/quicktype-core/src/UnionBuilder.ts | 24 +++-- .../src/attributes/AccessorNames.ts | 18 ++-- .../src/attributes/Constraints.ts | 9 +- .../src/attributes/Description.ts | 21 +++-- .../src/attributes/EnumValues.ts | 8 +- .../src/attributes/StringTypes.ts | 23 ++--- .../src/attributes/TypeAttributes.ts | 6 +- .../src/attributes/TypeNames.ts | 10 +-- .../src/attributes/URIAttributes.ts | 8 +- packages/quicktype-core/src/index.ts | 16 ++-- .../src/input/CompressedJSON.ts | 11 ++- .../src/input/FetchingJSONSchemaStore.ts | 5 +- .../quicktype-core/src/input/Inference.ts | 26 +++--- packages/quicktype-core/src/input/Inputs.ts | 19 ++-- .../src/input/JSONSchemaInput.ts | 84 +++++++++-------- .../src/input/JSONSchemaStore.ts | 3 +- .../src/input/PostmanCollection.ts | 1 + .../quicktype-core/src/input/io/NodeIO.ts | 13 +-- .../src/input/io/get-stream/buffer-stream.ts | 3 +- .../src/input/io/get-stream/index.ts | 1 + packages/quicktype-core/src/language/All.ts | 42 +++++---- packages/quicktype-core/src/language/CJSON.ts | 29 +++--- .../quicktype-core/src/language/CPlusPlus.ts | 90 +++++++++++-------- .../quicktype-core/src/language/CSharp.ts | 85 ++++++++++-------- .../quicktype-core/src/language/Crystal.ts | 35 ++++---- packages/quicktype-core/src/language/Dart.ts | 46 +++++----- packages/quicktype-core/src/language/Elm.ts | 48 +++++----- .../quicktype-core/src/language/Golang.ts | 34 ++++--- .../quicktype-core/src/language/Haskell.ts | 44 ++++----- .../quicktype-core/src/language/JSONSchema.ts | 33 +++---- packages/quicktype-core/src/language/Java.ts | 35 +++++--- .../quicktype-core/src/language/JavaScript.ts | 48 +++++----- .../src/language/JavaScriptPropTypes.ts | 37 ++++---- .../quicktype-core/src/language/Kotlin.ts | 31 ++++--- .../src/language/Objective-C.ts | 49 +++++----- packages/quicktype-core/src/language/Php.ts | 19 ++-- packages/quicktype-core/src/language/Pike.ts | 16 ++-- .../quicktype-core/src/language/Python.ts | 73 +++++++-------- packages/quicktype-core/src/language/Rust.ts | 39 ++++---- .../quicktype-core/src/language/Scala3.ts | 26 +++--- .../quicktype-core/src/language/Smithy4s.ts | 26 +++--- packages/quicktype-core/src/language/Swift.ts | 77 ++++++++-------- .../src/language/TypeScriptEffectSchema.ts | 21 +++-- .../src/language/TypeScriptFlow.ts | 29 +++--- .../src/language/TypeScriptZod.ts | 33 +++---- .../quicktype-core/src/language/ruby/index.ts | 62 +++++++------ .../src/rewrites/CombineClasses.ts | 8 +- .../src/rewrites/ExpandStrings.ts | 20 ++--- .../src/rewrites/FlattenStrings.ts | 10 +-- .../src/rewrites/FlattenUnions.ts | 18 ++-- .../quicktype-core/src/rewrites/InferMaps.ts | 14 ++- .../src/rewrites/ReplaceObjectType.ts | 10 +-- .../src/rewrites/ResolveIntersections.ts | 41 +++++---- .../quicktype-core/src/support/Acronyms.ts | 16 ++-- .../quicktype-core/src/support/Strings.ts | 10 ++- .../quicktype-core/src/support/Support.ts | 3 +- packages/quicktype-graphql-input/src/index.ts | 40 ++++----- .../quicktype-typescript-input/src/index.ts | 15 ++-- src/CompressedJSONFromStream.ts | 4 +- src/GraphQLIntrospection.ts | 16 ++-- src/TypeSource.ts | 2 +- src/URLGrammar.ts | 8 +- src/index.ts | 74 ++++++++------- 83 files changed, 1139 insertions(+), 1043 deletions(-) diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index bcb6a9304..8de7ac678 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -1,38 +1,40 @@ import { - setUnion, - setFilter, iterableEnumerate, iterableSome, mapFilter, - mapSortBy, mapFilterMap, - mapSome + mapSome, + mapSortBy, + setFilter, + setUnion } from "collection-utils"; +import _wordwrap from "wordwrap"; -import { type Type, type TypeKind, type ClassProperty } from "./Type"; -import { ClassType, EnumType, UnionType, MapType, ObjectType } from "./Type"; -import { separateNamedTypes, nullableFromUnion, matchTypeExhaustive, isNamedType } from "./TypeUtils"; -import { type Name, type Namer } from "./Naming"; -import { Namespace, FixedName, SimpleName, DependencyName, keywordNamespace } from "./Naming"; -import { type BlankLineConfig, type RenderContext, type ForEachPosition } from "./Renderer"; -import { Renderer } from "./Renderer"; -import { defined, panic, nonNull, assert } from "./support/Support"; -import { trimEnd } from "./support/Strings"; -import { type Sourcelike } from "./Source"; -import { sourcelikeToSource, serializeRenderResult } from "./Source"; - -import { type DeclarationIR, type Declaration } from "./DeclarationIR"; -import { declarationsForGraph, cycleBreakerTypesForGraph } from "./DeclarationIR"; -import { TypeAttributeStoreView } from "./TypeGraph"; -import { TypeAttributeKind } from "./attributes/TypeAttributes"; +import { enumCaseNames, getAccessorName, objectPropertyNames, unionMemberName } from "./attributes/AccessorNames"; import { descriptionTypeAttributeKind, propertyDescriptionsTypeAttributeKind } from "./attributes/Description"; -import { enumCaseNames, objectPropertyNames, unionMemberName, getAccessorName } from "./attributes/AccessorNames"; -import { type Transformation } from "./Transformers"; -import { transformationForType, followTargetType } from "./Transformers"; +import { TypeAttributeKind } from "./attributes/TypeAttributes"; +import { type Declaration, type DeclarationIR, cycleBreakerTypesForGraph, declarationsForGraph } from "./DeclarationIR"; +import { DependencyName, FixedName, type Name, type Namer, Namespace, SimpleName, keywordNamespace } from "./Naming"; +import { type BlankLineConfig, type ForEachPosition, type RenderContext, Renderer } from "./Renderer"; +import { type Sourcelike, serializeRenderResult, sourcelikeToSource } from "./Source"; +import { type Comment, type CommentOptions, isStringComment } from "./support/Comments"; +import { trimEnd } from "./support/Strings"; +import { assert, defined, nonNull, panic } from "./support/Support"; import { type TargetLanguage } from "./TargetLanguage"; -import { type Comment, isStringComment, type CommentOptions } from "./support/Comments"; +import { type Transformation, followTargetType, transformationForType } from "./Transformers"; +import { + type ClassProperty, + ClassType, + EnumType, + MapType, + ObjectType, + type Type, + type TypeKind, + UnionType +} from "./Type"; +import { TypeAttributeStoreView } from "./TypeGraph"; +import { isNamedType, matchTypeExhaustive, nullableFromUnion, separateNamedTypes } from "./TypeUtils"; -import _wordwrap from "wordwrap"; const wordWrap: (s: string) => string = _wordwrap(90); export const topLevelNameOrder = 1; diff --git a/packages/quicktype-core/src/DeclarationIR.ts b/packages/quicktype-core/src/DeclarationIR.ts index 47d53d2de..f3f15ce0f 100644 --- a/packages/quicktype-core/src/DeclarationIR.ts +++ b/packages/quicktype-core/src/DeclarationIR.ts @@ -1,10 +1,10 @@ -import { setUnionInto, setFilter, iterableFirst, setSubtract, setIntersect } from "collection-utils"; +import { iterableFirst, setFilter, setIntersect, setSubtract, setUnionInto } from "collection-utils"; -import { type TypeGraph } from "./TypeGraph"; -import { type Type } from "./Type"; -import { panic, defined, assert } from "./support/Support"; import { Graph } from "./Graph"; import { messageError } from "./Messages"; +import { assert, defined, panic } from "./support/Support"; +import { type Type } from "./Type"; +import { type TypeGraph } from "./TypeGraph"; export type DeclarationKind = "forward" | "define"; diff --git a/packages/quicktype-core/src/GatherNames.ts b/packages/quicktype-core/src/GatherNames.ts index e5b7d3b86..2dba2afb3 100644 --- a/packages/quicktype-core/src/GatherNames.ts +++ b/packages/quicktype-core/src/GatherNames.ts @@ -1,13 +1,12 @@ +import { setMap, setSortBy, setUnion } from "collection-utils"; import * as pluralize from "pluralize"; -import { setUnion, setMap, setSortBy } from "collection-utils"; +import { TooManyTypeNames, TypeNames, namesTypeAttributeKind, tooManyNamesThreshold } from "./attributes/TypeNames"; +import { assert, defined, panic } from "./support/Support"; +import { transformationForType } from "./Transformers"; +import { ObjectType, type Type } from "./Type"; import { type TypeGraph } from "./TypeGraph"; -import { type Type } from "./Type"; -import { ObjectType } from "./Type"; import { matchCompoundType, nullableFromUnion } from "./TypeUtils"; -import { TypeNames, namesTypeAttributeKind, TooManyTypeNames, tooManyNamesThreshold } from "./attributes/TypeNames"; -import { defined, panic, assert } from "./support/Support"; -import { transformationForType } from "./Transformers"; class UniqueQueue { private readonly _present = new Set(); diff --git a/packages/quicktype-core/src/Graph.ts b/packages/quicktype-core/src/Graph.ts index c54e3ed05..df186ce9c 100644 --- a/packages/quicktype-core/src/Graph.ts +++ b/packages/quicktype-core/src/Graph.ts @@ -1,6 +1,6 @@ import { setMap } from "collection-utils"; -import { defined, repeated, assert, repeatedCall } from "./support/Support"; +import { assert, defined, repeated, repeatedCall } from "./support/Support"; function countComponentGraphNodes(components: number[][]): number { if (components.length === 0) return 0; diff --git a/packages/quicktype-core/src/GraphRewriting.ts b/packages/quicktype-core/src/GraphRewriting.ts index e60360890..546877575 100644 --- a/packages/quicktype-core/src/GraphRewriting.ts +++ b/packages/quicktype-core/src/GraphRewriting.ts @@ -1,14 +1,20 @@ -import { mapMap, EqualityMap } from "collection-utils"; - -import { type PrimitiveTypeKind, type Type, type ClassProperty, type MaybeTypeIdentity } from "./Type"; +import { EqualityMap, mapMap } from "collection-utils"; + +import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +import { assert, indentationString, panic } from "./support/Support"; +import { type ClassProperty, type MaybeTypeIdentity, type PrimitiveTypeKind, type Type } from "./Type"; +// eslint-disable-next-line import/no-cycle +import { type StringTypeMapping, TypeBuilder } from "./TypeBuilder"; +import { + type TypeGraph, + type TypeRef, + assertTypeRefGraph, + derefTypeRef, + isTypeRef, + typeAndAttributesForTypeRef, + typeRefIndex +} from "./TypeGraph"; import { combineTypeAttributesOfTypes } from "./TypeUtils"; -import { type TypeGraph, type TypeRef } from "./TypeGraph"; -import { derefTypeRef, typeAndAttributesForTypeRef, assertTypeRefGraph, typeRefIndex, isTypeRef } from "./TypeGraph"; -import { type TypeAttributes } from "./attributes/TypeAttributes"; -import { emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; -import { assert, panic, indentationString } from "./support/Support"; -import { type StringTypeMapping } from "./TypeBuilder"; -import { TypeBuilder } from "./TypeBuilder"; export interface TypeLookerUp { lookupTypeRefs: (typeRefs: TypeRef[], forwardingRef?: TypeRef) => TypeRef | undefined; diff --git a/packages/quicktype-core/src/MakeTransformations.ts b/packages/quicktype-core/src/MakeTransformations.ts index 0b5de7301..fc3bf23f5 100644 --- a/packages/quicktype-core/src/MakeTransformations.ts +++ b/packages/quicktype-core/src/MakeTransformations.ts @@ -1,39 +1,40 @@ -import { setFilter, iterableFirst, mapMapEntries, withDefault, iterableSome, arraySortByInto } from "collection-utils"; +import { arraySortByInto, iterableFirst, iterableSome, mapMapEntries, setFilter, withDefault } from "collection-utils"; -import { type TypeGraph, type TypeRef } from "./TypeGraph"; -import { typeRefIndex } from "./TypeGraph"; +import { minMaxLengthForType, minMaxValueForType } from "./attributes/Constraints"; +import { StringTypes } from "./attributes/StringTypes"; +import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +import { type GraphRewriteBuilder } from "./GraphRewriting"; +import { type RunContext } from "./Run"; +import { assert, defined, panic } from "./support/Support"; import { type TargetLanguage } from "./TargetLanguage"; -import { type TypeKind, type Type, type PrimitiveType, type PrimitiveStringTypeKind } from "./Type"; import { - UnionType, - EnumType, + ArrayDecodingTransformer, + ChoiceTransformer, + DecodingChoiceTransformer, + DecodingTransformer, + MinMaxLengthCheckTransformer, + MinMaxValueTransformer, + ParseStringTransformer, + StringMatchTransformer, + StringProducerTransformer, + Transformation, + type Transformer, + UnionInstantiationTransformer, + transformationTypeAttributeKind +} from "./Transformers"; +import { ArrayType, + EnumType, + type PrimitiveStringTypeKind, + type PrimitiveType, + type Type, + type TypeKind, + UnionType, isNumberTypeKind, isPrimitiveStringTypeKind, targetTypeKindForTransformedStringTypeKind } from "./Type"; -import { type GraphRewriteBuilder } from "./GraphRewriting"; -import { defined, assert, panic } from "./support/Support"; -import { type Transformer } from "./Transformers"; -import { - UnionInstantiationTransformer, - DecodingChoiceTransformer, - Transformation, - transformationTypeAttributeKind, - StringMatchTransformer, - StringProducerTransformer, - ChoiceTransformer, - DecodingTransformer, - ParseStringTransformer, - ArrayDecodingTransformer, - MinMaxLengthCheckTransformer, - MinMaxValueTransformer -} from "./Transformers"; -import { type TypeAttributes } from "./attributes/TypeAttributes"; -import { emptyTypeAttributes, combineTypeAttributes } from "./attributes/TypeAttributes"; -import { StringTypes } from "./attributes/StringTypes"; -import { type RunContext } from "./Run"; -import { minMaxLengthForType, minMaxValueForType } from "./attributes/Constraints"; +import { type TypeGraph, type TypeRef, typeRefIndex } from "./TypeGraph"; function transformationAttributes( graph: TypeGraph, diff --git a/packages/quicktype-core/src/MarkovChain.ts b/packages/quicktype-core/src/MarkovChain.ts index a2e6f453b..9a3fa5f84 100644 --- a/packages/quicktype-core/src/MarkovChain.ts +++ b/packages/quicktype-core/src/MarkovChain.ts @@ -1,5 +1,5 @@ -import { panic, assert, inflateBase64 } from "./support/Support"; import { encodedMarkovChain } from "./EncodedMarkovChain"; +import { assert, inflateBase64, panic } from "./support/Support"; // This must be null, not undefined, because we read it from JSON. export type SubTrie = number | null | Trie; diff --git a/packages/quicktype-core/src/Messages.ts b/packages/quicktype-core/src/Messages.ts index 0236235f9..6f35dae1c 100644 --- a/packages/quicktype-core/src/Messages.ts +++ b/packages/quicktype-core/src/Messages.ts @@ -1,14 +1,14 @@ -import { type StringMap } from "./support/Support"; import { type Ref } from "./input/JSONSchemaInput"; +import { type StringMap } from "./support/Support"; export type ErrorProperties = | { kind: "InternalError"; properties: { message: string } } // Misc | { - kind: "MiscJSONParseError"; - properties: { address: string; description: string; message: string }; - } + kind: "MiscJSONParseError"; + properties: { address: string; description: string; message: string }; + } | { kind: "MiscReadError"; properties: { fileOrURL: string; message: string } } | { kind: "MiscUnicodeHighSurrogateWithoutLowSurrogate"; properties: {} } | { kind: "MiscInvalidMinMaxConstraint"; properties: { max: number; min: number } } @@ -36,9 +36,9 @@ export type ErrorProperties = | { kind: "SchemaIDMustHaveAddress"; properties: { id: string; ref: Ref } } | { kind: "SchemaWrongAccessorEntryArrayLength"; properties: { operation: string; ref: Ref } } | { - kind: "SchemaSetOperationCasesIsNotArray"; - properties: { cases: any; operation: string; ref: Ref }; - } + kind: "SchemaSetOperationCasesIsNotArray"; + properties: { cases: any; operation: string; ref: Ref }; + } | { kind: "SchemaMoreThanOneUnionMemberName"; properties: { names: string[] } } | { kind: "SchemaCannotGetTypesFromBoolean"; properties: { ref: string } } | { kind: "SchemaCannotIndexArrayWithNonNumber"; properties: { actual: string; ref: Ref } } diff --git a/packages/quicktype-core/src/Naming.ts b/packages/quicktype-core/src/Naming.ts index f49ad815b..d23dd30fc 100644 --- a/packages/quicktype-core/src/Naming.ts +++ b/packages/quicktype-core/src/Naming.ts @@ -1,19 +1,19 @@ import { - setUnion, - setUnionInto, - setMap, - setFilter, + iterableEvery, iterableFind, - iterableSome, + iterableFirst, iterableMinBy, - setGroupBy, + iterableSome, + mapMergeInto, + setFilter, setFilterMap, - iterableFirst, - iterableEvery, - mapMergeInto + setGroupBy, + setMap, + setUnion, + setUnionInto } from "collection-utils"; -import { defined, assert, panic } from "./support/Support"; +import { assert, defined, panic } from "./support/Support"; export class Namespace { public readonly forbiddenNamespaces: ReadonlySet; diff --git a/packages/quicktype-core/src/Renderer.ts b/packages/quicktype-core/src/Renderer.ts index f22dc7c0a..9c8f04e6d 100644 --- a/packages/quicktype-core/src/Renderer.ts +++ b/packages/quicktype-core/src/Renderer.ts @@ -1,15 +1,12 @@ import { iterableEnumerate } from "collection-utils"; -import { type TypeGraph } from "./TypeGraph"; -import { type Name, type Namespace } from "./Naming"; -import { assignNames } from "./Naming"; -import { type Source, type Sourcelike, type NewlineSource } from "./Source"; -import { annotated, sourcelikeToSource, newline } from "./Source"; -import { type AnnotationData } from "./Annotation"; -import { IssueAnnotationData } from "./Annotation"; +import { type AnnotationData, IssueAnnotationData } from "./Annotation"; +import { type Name, type Namespace, assignNames } from "./Naming"; +import { type NewlineSource, type Source, type Sourcelike, annotated, newline, sourcelikeToSource } from "./Source"; +import { type Comment } from "./support/Comments"; import { assert, panic } from "./support/Support"; import { type TargetLanguage } from "./TargetLanguage"; -import { type Comment } from "./support/Comments"; +import { type TypeGraph } from "./TypeGraph"; export interface RenderResult { names: ReadonlyMap; diff --git a/packages/quicktype-core/src/RendererOptions.ts b/packages/quicktype-core/src/RendererOptions.ts index 4aab7d4ec..9e4b17542 100644 --- a/packages/quicktype-core/src/RendererOptions.ts +++ b/packages/quicktype-core/src/RendererOptions.ts @@ -1,7 +1,9 @@ -import { assert } from "./support/Support"; -import { messageError } from "./Messages"; +// eslint-disable-next-line @typescript-eslint/no-redeclare import { hasOwnProperty } from "collection-utils"; +import { messageError } from "./Messages"; +import { assert } from "./support/Support"; + /** * Primary options show up in the web UI in the "Language" settings tab, * secondary options in "Other". diff --git a/packages/quicktype-core/src/Run.ts b/packages/quicktype-core/src/Run.ts index 2e2790781..42a5e5b31 100644 --- a/packages/quicktype-core/src/Run.ts +++ b/packages/quicktype-core/src/Run.ts @@ -1,27 +1,25 @@ import { mapFirst } from "collection-utils"; -import * as targetLanguages from "./language/All"; -import { type TargetLanguage, type MultiFileRenderResult } from "./TargetLanguage"; -import { type SerializedRenderResult, type Annotation, type Location, type Span } from "./Source"; -import { assert } from "./support/Support"; -import { combineClasses } from "./rewrites/CombineClasses"; -import { inferMaps } from "./rewrites/InferMaps"; -import { type StringTypeMapping } from "./TypeBuilder"; -import { TypeBuilder } from "./TypeBuilder"; -import { type TypeGraph } from "./TypeGraph"; -import { noneToAny, optionalToNullable, removeIndirectionIntersections } from "./TypeGraph"; import { initTypeNames } from "./attributes/TypeNames"; import { gatherNames } from "./GatherNames"; +import { InputData } from "./input/Inputs"; +import * as targetLanguages from "./language/All"; +import { makeTransformations } from "./MakeTransformations"; +import { messageError } from "./Messages"; +import { combineClasses } from "./rewrites/CombineClasses"; import { expandStrings } from "./rewrites/ExpandStrings"; +import { flattenStrings } from "./rewrites/FlattenStrings"; import { flattenUnions } from "./rewrites/FlattenUnions"; -import { resolveIntersections } from "./rewrites/ResolveIntersections"; +import { inferMaps } from "./rewrites/InferMaps"; import { replaceObjectType } from "./rewrites/ReplaceObjectType"; -import { messageError } from "./Messages"; -import { InputData } from "./input/Inputs"; -import { flattenStrings } from "./rewrites/FlattenStrings"; -import { makeTransformations } from "./MakeTransformations"; -import { type TransformedStringTypeKind } from "./Type"; +import { resolveIntersections } from "./rewrites/ResolveIntersections"; +import { type Annotation, type Location, type SerializedRenderResult, type Span } from "./Source"; import { type Comment } from "./support/Comments"; +import { assert } from "./support/Support"; +import { type MultiFileRenderResult, type TargetLanguage } from "./TargetLanguage"; +import { type TransformedStringTypeKind } from "./Type"; +import { type StringTypeMapping, TypeBuilder } from "./TypeBuilder"; +import { type TypeGraph, noneToAny, optionalToNullable, removeIndirectionIntersections } from "./TypeGraph"; export function getTargetLanguage(nameOrInstance: string | TargetLanguage): TargetLanguage { if (typeof nameOrInstance === "object") { diff --git a/packages/quicktype-core/src/Source.ts b/packages/quicktype-core/src/Source.ts index f47360c37..fcf004546 100644 --- a/packages/quicktype-core/src/Source.ts +++ b/packages/quicktype-core/src/Source.ts @@ -2,8 +2,8 @@ import { arrayIntercalate, iterableMax, withDefault } from "collection-utils"; import { type AnnotationData } from "./Annotation"; import { Name } from "./Naming"; -import { defined, assertNever, panic, assert } from "./support/Support"; import { repeatString } from "./support/Strings"; +import { assert, assertNever, defined, panic } from "./support/Support"; export type Source = | TextSource diff --git a/packages/quicktype-core/src/TargetLanguage.ts b/packages/quicktype-core/src/TargetLanguage.ts index 7f41b919e..07fe51409 100644 --- a/packages/quicktype-core/src/TargetLanguage.ts +++ b/packages/quicktype-core/src/TargetLanguage.ts @@ -1,17 +1,15 @@ import { mapMap } from "collection-utils"; -import { type TypeGraph } from "./TypeGraph"; -import { type Renderer, type RenderContext } from "./Renderer"; -import { type OptionDefinition, type Option } from "./RendererOptions"; -import { type SerializedRenderResult } from "./Source"; -import { serializeRenderResult } from "./Source"; -import { type StringTypeMapping } from "./TypeBuilder"; -import { defined } from "./support/Support"; import { type ConvenienceRenderer } from "./ConvenienceRenderer"; -import { type Type } from "./Type"; -import { type DateTimeRecognizer } from "./DateTime"; -import { DefaultDateTimeRecognizer } from "./DateTime"; +import { type DateTimeRecognizer, DefaultDateTimeRecognizer } from "./DateTime"; +import { type RenderContext, type Renderer } from "./Renderer"; +import { type Option, type OptionDefinition } from "./RendererOptions"; +import { type SerializedRenderResult, serializeRenderResult } from "./Source"; import { type Comment } from "./support/Comments"; +import { defined } from "./support/Support"; +import { type Type } from "./Type"; +import { type StringTypeMapping } from "./TypeBuilder"; +import { type TypeGraph } from "./TypeGraph"; export type MultiFileRenderResult = ReadonlyMap; diff --git a/packages/quicktype-core/src/Transformers.ts b/packages/quicktype-core/src/Transformers.ts index 3c9b3f9eb..01de933a8 100644 --- a/packages/quicktype-core/src/Transformers.ts +++ b/packages/quicktype-core/src/Transformers.ts @@ -1,21 +1,19 @@ import { - setUnionInto, + addHashCode, areEqual, - hashCodeOf, + arraySortByInto, definedMap, - addHashCode, definedMapWithDefault, - arraySortByInto, - hashString + hashCodeOf, + hashString, + setUnionInto } from "collection-utils"; -import { type Type, type TypeKind } from "./Type"; -import { UnionType, EnumType, PrimitiveType } from "./Type"; import { TypeAttributeKind } from "./attributes/TypeAttributes"; -import { panic, assert, indentationString } from "./support/Support"; import { type BaseGraphRewriteBuilder } from "./GraphRewriting"; -import { type TypeRef, type TypeGraph } from "./TypeGraph"; -import { derefTypeRef } from "./TypeGraph"; +import { assert, indentationString, panic } from "./support/Support"; +import { EnumType, PrimitiveType, type Type, type TypeKind, UnionType } from "./Type"; +import { type TypeGraph, type TypeRef, derefTypeRef } from "./TypeGraph"; function debugStringForType(t: Type): string { const target = followTargetType(t); diff --git a/packages/quicktype-core/src/Type.ts b/packages/quicktype-core/src/Type.ts index 6b50cd7d9..6184f712b 100644 --- a/packages/quicktype-core/src/Type.ts +++ b/packages/quicktype-core/src/Type.ts @@ -1,35 +1,35 @@ import { + addHashCode, + areEqual, + definedMap, + // eslint-disable-next-line @typescript-eslint/no-redeclare + hasOwnProperty, + hashCodeInit, + hashCodeOf, iterableEvery, iterableFind, iterableSome, - toReadonlySet, - hashCodeOf, - areEqual, + mapFilter, + mapFromObject, mapMap, - setMap, - mapSortByKey, mapSome, - mapFilter, - setSortBy, + mapSortByKey, + mapSortToArray, setFilter, + setMap, + setSortBy, setUnionInto, - mapSortToArray, - definedMap, - hashCodeInit, - addHashCode, - hasOwnProperty, - mapFromObject + toReadonlySet } from "collection-utils"; -import { defined, panic, assert } from "./support/Support"; -import { type TypeReconstituter, type BaseGraphRewriteBuilder } from "./GraphRewriting"; -import { type TypeNames } from "./attributes/TypeNames"; -import { namesTypeAttributeKind } from "./attributes/TypeNames"; import { type TypeAttributes } from "./attributes/TypeAttributes"; -import { messageAssert } from "./Messages"; -import { type TypeRef, type TypeGraph } from "./TypeGraph"; -import { attributesForTypeRef, derefTypeRef, typeRefIndex } from "./TypeGraph"; +import { type TypeNames, namesTypeAttributeKind } from "./attributes/TypeNames"; import { uriInferenceAttributesProducer } from "./attributes/URIAttributes"; +import { type BaseGraphRewriteBuilder, type TypeReconstituter } from "./GraphRewriting"; +import { messageAssert } from "./Messages"; +import { assert, defined, panic } from "./support/Support"; +// eslint-disable-next-line import/no-cycle +import { type TypeGraph, type TypeRef, attributesForTypeRef, derefTypeRef, typeRefIndex } from "./TypeGraph"; /** * `jsonSchema` is the `format` to be used to represent this string type in diff --git a/packages/quicktype-core/src/TypeBuilder.ts b/packages/quicktype-core/src/TypeBuilder.ts index 5370e5be8..2b4275be8 100644 --- a/packages/quicktype-core/src/TypeBuilder.ts +++ b/packages/quicktype-core/src/TypeBuilder.ts @@ -1,51 +1,54 @@ import { EqualityMap, - mapMap, - mapSortByKey, + areEqual, + definedMap, iterableEvery, mapFilter, mapFind, - areEqual, + mapMap, + mapSortByKey, setUnionManyInto, - definedMap, withDefault } from "collection-utils"; +// eslint-disable-next-line import/no-cycle +import { StringTypes, stringTypesTypeAttributeKind } from "./attributes/StringTypes"; import { - type PrimitiveTypeKind, - type Type, - type PrimitiveStringTypeKind, - type MaybeTypeIdentity, - type TypeIdentity, - type TransformedStringTypeKind, - type TypeKind -} from "./Type"; + TypeAttributeKind, + type TypeAttributes, + combineTypeAttributes, + emptyTypeAttributes +} from "./attributes/TypeAttributes"; +import { assert, defined, panic } from "./support/Support"; +// eslint-disable-next-line import/no-cycle import { - PrimitiveType, - EnumType, - MapType, ArrayType, - ClassType, - UnionType, ClassProperty, + ClassType, + EnumType, IntersectionType, + MapType, + type MaybeTypeIdentity, ObjectType, - primitiveTypeIdentity, - enumTypeIdentity, - mapTypeIdentify, + type PrimitiveStringTypeKind, + PrimitiveType, + type PrimitiveTypeKind, + type TransformedStringTypeKind, + type Type, + type TypeIdentity, + type TypeKind, + UnionType, arrayTypeIdentity, classTypeIdentity, - unionTypeIdentity, + enumTypeIdentity, intersectionTypeIdentity, isPrimitiveStringTypeKind, - transformedStringTypeKinds + mapTypeIdentify, + primitiveTypeIdentity, + transformedStringTypeKinds, + unionTypeIdentity } from "./Type"; -import { type TypeRef } from "./TypeGraph"; -import { TypeGraph, makeTypeRef, derefTypeRef, typeRefIndex, assertTypeRefGraph } from "./TypeGraph"; -import { type TypeAttributes } from "./attributes/TypeAttributes"; -import { combineTypeAttributes, TypeAttributeKind, emptyTypeAttributes } from "./attributes/TypeAttributes"; -import { defined, assert, panic } from "./support/Support"; -import { stringTypesTypeAttributeKind, StringTypes } from "./attributes/StringTypes"; +import { TypeGraph, type TypeRef, assertTypeRefGraph, derefTypeRef, makeTypeRef, typeRefIndex } from "./TypeGraph"; // FIXME: Don't infer provenance. All original types should be present in // non-inferred form in the final graph. diff --git a/packages/quicktype-core/src/TypeGraph.ts b/packages/quicktype-core/src/TypeGraph.ts index 2e5ddb1c4..98df9370f 100644 --- a/packages/quicktype-core/src/TypeGraph.ts +++ b/packages/quicktype-core/src/TypeGraph.ts @@ -1,19 +1,22 @@ -import { iterableFirst, setFilter, setUnionManyInto, setSubtract, mapMap, mapSome, setMap } from "collection-utils"; - -import { type Type } from "./Type"; -import { ClassType, UnionType, IntersectionType } from "./Type"; -import { type SeparatedNamedTypes } from "./TypeUtils"; -import { separateNamedTypes, isNamedType, combineTypeAttributesOfTypes } from "./TypeUtils"; -import { defined, assert, panic, mustNotHappen } from "./support/Support"; -import { type TypeBuilder, type StringTypeMapping } from "./TypeBuilder"; -import { getNoStringTypeMapping, provenanceTypeAttributeKind } from "./TypeBuilder"; -import { type BaseGraphRewriteBuilder } from "./GraphRewriting"; -import { GraphRewriteBuilder, GraphRemapBuilder } from "./GraphRewriting"; +import { iterableFirst, mapMap, mapSome, setFilter, setMap, setSubtract, setUnionManyInto } from "collection-utils"; + +import { type TypeAttributeKind, type TypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; import { TypeNames, namesTypeAttributeKind } from "./attributes/TypeNames"; import { Graph } from "./Graph"; -import { type TypeAttributeKind, type TypeAttributes } from "./attributes/TypeAttributes"; -import { emptyTypeAttributes } from "./attributes/TypeAttributes"; +// eslint-disable-next-line import/no-cycle +import { type BaseGraphRewriteBuilder, GraphRemapBuilder, GraphRewriteBuilder } from "./GraphRewriting"; import { messageError } from "./Messages"; +import { assert, defined, mustNotHappen, panic } from "./support/Support"; +// eslint-disable-next-line import/no-cycle +import { ClassType, IntersectionType, type Type, UnionType } from "./Type"; +// eslint-disable-next-line import/no-cycle +import { + type StringTypeMapping, + type TypeBuilder, + getNoStringTypeMapping, + provenanceTypeAttributeKind +} from "./TypeBuilder"; +import { type SeparatedNamedTypes, combineTypeAttributesOfTypes, isNamedType, separateNamedTypes } from "./TypeUtils"; export type TypeRef = number; diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index 5a37546bd..07fdd4e65 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -1,12 +1,27 @@ -import { setFilter, setSortBy, iterableFirst, setUnion, EqualityMap } from "collection-utils"; - -import { defined, panic, assert, assertNever } from "./support/Support"; -import { type TypeAttributes, type CombinationKind } from "./attributes/TypeAttributes"; -import { combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; -import { type Type, type PrimitiveType, type ClassProperty, type SetOperationType } from "./Type"; -import { ArrayType, EnumType, ObjectType, MapType, ClassType, UnionType, isPrimitiveStringTypeKind } from "./Type"; -import { type StringTypes } from "./attributes/StringTypes"; -import { stringTypesTypeAttributeKind } from "./attributes/StringTypes"; +import { EqualityMap, iterableFirst, setFilter, setSortBy, setUnion } from "collection-utils"; + +// eslint-disable-next-line import/no-cycle +import { type StringTypes, stringTypesTypeAttributeKind } from "./attributes/StringTypes"; +import { + type CombinationKind, + type TypeAttributes, + combineTypeAttributes, + emptyTypeAttributes +} from "./attributes/TypeAttributes"; +import { assert, assertNever, defined, panic } from "./support/Support"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + MapType, + ObjectType, + type PrimitiveType, + type SetOperationType, + type Type, + UnionType, + isPrimitiveStringTypeKind +} from "./Type"; export function assertIsObject(t: Type): ObjectType { if (t instanceof ObjectType) { diff --git a/packages/quicktype-core/src/UnifyClasses.ts b/packages/quicktype-core/src/UnifyClasses.ts index dbf5fa4b2..f1e6ab3e0 100644 --- a/packages/quicktype-core/src/UnifyClasses.ts +++ b/packages/quicktype-core/src/UnifyClasses.ts @@ -1,16 +1,13 @@ import { iterableFirst, setUnionInto } from "collection-utils"; -import { type Type, type ClassProperty, type ObjectType } from "./Type"; -import { UnionType } from "./Type"; -import { assertIsObject } from "./TypeUtils"; +import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +import { type BaseGraphRewriteBuilder, type GraphRewriteBuilder, type TypeLookerUp } from "./GraphRewriting"; +import { assert, defined, panic } from "./support/Support"; +import { type ClassProperty, type ObjectType, type Type, UnionType } from "./Type"; import { type TypeBuilder } from "./TypeBuilder"; -import { type TypeLookerUp, type GraphRewriteBuilder, type BaseGraphRewriteBuilder } from "./GraphRewriting"; -import { UnionBuilder, TypeRefUnionAccumulator } from "./UnionBuilder"; -import { panic, assert, defined } from "./support/Support"; -import { type TypeAttributes } from "./attributes/TypeAttributes"; -import { combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; -import { type TypeRef } from "./TypeGraph"; -import { derefTypeRef } from "./TypeGraph"; +import { type TypeRef, derefTypeRef } from "./TypeGraph"; +import { assertIsObject } from "./TypeUtils"; +import { TypeRefUnionAccumulator, UnionBuilder } from "./UnionBuilder"; function getCliqueProperties( clique: ObjectType[], diff --git a/packages/quicktype-core/src/UnionBuilder.ts b/packages/quicktype-core/src/UnionBuilder.ts index 0573b18b7..4c93a6ac6 100644 --- a/packages/quicktype-core/src/UnionBuilder.ts +++ b/packages/quicktype-core/src/UnionBuilder.ts @@ -1,19 +1,25 @@ -import { mapMerge, mapUpdateInto, mapMap, setUnionInto } from "collection-utils"; +import { mapMap, mapMerge, mapUpdateInto, setUnionInto } from "collection-utils"; -import { type TypeKind, type PrimitiveStringTypeKind, type Type, type PrimitiveTypeKind } from "./Type"; -import { UnionType, isPrimitiveTypeKind } from "./Type"; -import { matchTypeExhaustive } from "./TypeUtils"; -import { type TypeAttributes } from "./attributes/TypeAttributes"; +import { StringTypes, stringTypesTypeAttributeKind } from "./attributes/StringTypes"; import { + type TypeAttributes, combineTypeAttributes, emptyTypeAttributes, - makeTypeAttributesInferred, - increaseTypeAttributesDistance + increaseTypeAttributesDistance, + makeTypeAttributesInferred } from "./attributes/TypeAttributes"; -import { defined, assert, panic, assertNever } from "./support/Support"; +import { assert, assertNever, defined, panic } from "./support/Support"; +import { + type PrimitiveStringTypeKind, + type PrimitiveTypeKind, + type Type, + type TypeKind, + UnionType, + isPrimitiveTypeKind +} from "./Type"; import { type TypeBuilder } from "./TypeBuilder"; -import { StringTypes, stringTypesTypeAttributeKind } from "./attributes/StringTypes"; import { type TypeRef } from "./TypeGraph"; +import { matchTypeExhaustive } from "./TypeUtils"; // FIXME: This interface is badly designed. All the properties // should use immutable types, and getMemberKinds should be diff --git a/packages/quicktype-core/src/attributes/AccessorNames.ts b/packages/quicktype-core/src/attributes/AccessorNames.ts index c9384cd56..cb19ca59e 100644 --- a/packages/quicktype-core/src/attributes/AccessorNames.ts +++ b/packages/quicktype-core/src/attributes/AccessorNames.ts @@ -1,19 +1,19 @@ import { iterableFirst, mapFromIterable, - mapMap, mapFromObject, - setUnionManyInto, - mapMergeInto + mapMap, + mapMergeInto, + setUnionManyInto } from "collection-utils"; -import { type TypeAttributes } from "./TypeAttributes"; -import { TypeAttributeKind } from "./TypeAttributes"; -import { defined, isStringMap, checkStringMap, checkArray } from "../support/Support"; -import { type EnumType, type UnionType, type Type, type ObjectType } from "../Type"; -import { messageAssert } from "../Messages"; +import { type JSONSchemaAttributes, type JSONSchemaType, type Ref } from "../input/JSONSchemaInput"; import { type JSONSchema } from "../input/JSONSchemaStore"; -import { type Ref, type JSONSchemaType, type JSONSchemaAttributes } from "../input/JSONSchemaInput"; +import { messageAssert } from "../Messages"; +import { checkArray, checkStringMap, defined, isStringMap } from "../support/Support"; +import { type EnumType, type ObjectType, type Type, type UnionType } from "../Type"; + +import { TypeAttributeKind, type TypeAttributes } from "./TypeAttributes"; export type AccessorEntry = string | Map; diff --git a/packages/quicktype-core/src/attributes/Constraints.ts b/packages/quicktype-core/src/attributes/Constraints.ts index 1bb66e2cf..09fb79564 100644 --- a/packages/quicktype-core/src/attributes/Constraints.ts +++ b/packages/quicktype-core/src/attributes/Constraints.ts @@ -1,9 +1,10 @@ +import { type JSONSchemaAttributes, type JSONSchemaType, type Ref } from "../input/JSONSchemaInput"; +import { type JSONSchema } from "../input/JSONSchemaStore"; +import { messageError } from "../Messages"; +import { assert } from "../support/Support"; import { type Type, type TypeKind } from "../Type"; + import { TypeAttributeKind } from "./TypeAttributes"; -import { assert } from "../support/Support"; -import { messageError } from "../Messages"; -import { type JSONSchemaType, type JSONSchemaAttributes, type Ref } from "../input/JSONSchemaInput"; -import { type JSONSchema } from "../input/JSONSchemaStore"; // This can't be an object type, unfortunately, because it's in the // type's identity and as such must be comparable and hashable with diff --git a/packages/quicktype-core/src/attributes/Description.ts b/packages/quicktype-core/src/attributes/Description.ts index 9bf1d6588..01022e7dd 100644 --- a/packages/quicktype-core/src/attributes/Description.ts +++ b/packages/quicktype-core/src/attributes/Description.ts @@ -1,22 +1,29 @@ import { + iterableFirst, mapFilterMap, mapFromObject, - setUnion, - iterableFirst, - setUnionManyInto, mapMergeWithInto, - setSubtract + setSubtract, + setUnion, + setUnionManyInto } from "collection-utils"; // There's a cyclic import here. Ignoring now because it requires a large refactor. // skipcq: JS-E1008 -import { TypeAttributeKind, emptyTypeAttributes } from "./TypeAttributes"; // FIXME: This is a circular import -import { type JSONSchemaType, type Ref, type JSONSchemaAttributes, type PathElement } from "../input/JSONSchemaInput"; -import { PathElementKind } from "../input/JSONSchemaInput"; +// eslint-disable-next-line import/no-cycle +import { + type JSONSchemaAttributes, + type JSONSchemaType, + type PathElement, + PathElementKind, + type Ref +} from "../input/JSONSchemaInput"; import { type JSONSchema } from "../input/JSONSchemaStore"; import { type Type } from "../Type"; +import { TypeAttributeKind, emptyTypeAttributes } from "./TypeAttributes"; + export function addDescriptionToSchema( schema: { [name: string]: unknown }, description: Iterable | undefined diff --git a/packages/quicktype-core/src/attributes/EnumValues.ts b/packages/quicktype-core/src/attributes/EnumValues.ts index 38ac38542..1f66958e3 100644 --- a/packages/quicktype-core/src/attributes/EnumValues.ts +++ b/packages/quicktype-core/src/attributes/EnumValues.ts @@ -1,11 +1,11 @@ import { mapMap } from "collection-utils"; -import { type AccessorNames } from "./AccessorNames"; -import { lookupKey, makeAccessorNames } from "./AccessorNames"; +import { type JSONSchemaAttributes, type JSONSchemaType, type Ref } from "../input/JSONSchemaInput"; +import { type JSONSchema } from "../input/JSONSchemaStore"; import { type EnumType } from "../Type"; + +import { type AccessorNames, lookupKey, makeAccessorNames } from "./AccessorNames"; import { TypeAttributeKind } from "./TypeAttributes"; -import { type JSONSchema } from "../input/JSONSchemaStore"; -import { type Ref, type JSONSchemaType, type JSONSchemaAttributes } from "../input/JSONSchemaInput"; class EnumValuesTypeAttributeKind extends TypeAttributeKind { public constructor() { diff --git a/packages/quicktype-core/src/attributes/StringTypes.ts b/packages/quicktype-core/src/attributes/StringTypes.ts index 4c0083e82..343eeebe0 100644 --- a/packages/quicktype-core/src/attributes/StringTypes.ts +++ b/packages/quicktype-core/src/attributes/StringTypes.ts @@ -1,21 +1,22 @@ import { - mapMap, - iterableFirst, - setIntersect, - hashCodeOf, + addHashCode, areEqual, - mapMergeWithInto, definedMap, - addHashCode, + hashCodeOf, + iterableFirst, + mapMap, + mapMergeWithInto, + setIntersect, setUnionInto } from "collection-utils"; -import { TypeAttributeKind } from "./TypeAttributes"; -import { defined, assert } from "../support/Support"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { stringTypeMappingGet } from "../TypeBuilder"; -import { type TransformedStringTypeKind } from "../Type"; import { type DateTimeRecognizer } from "../DateTime"; +import { assert, defined } from "../support/Support"; +import { type TransformedStringTypeKind } from "../Type"; +// eslint-disable-next-line import/no-cycle +import { type StringTypeMapping, stringTypeMappingGet } from "../TypeBuilder"; + +import { TypeAttributeKind } from "./TypeAttributes"; export class StringTypes { public static readonly unrestricted: StringTypes = new StringTypes(undefined, new Set()); diff --git a/packages/quicktype-core/src/attributes/TypeAttributes.ts b/packages/quicktype-core/src/attributes/TypeAttributes.ts index bf5a35d5b..164f9878d 100644 --- a/packages/quicktype-core/src/attributes/TypeAttributes.ts +++ b/packages/quicktype-core/src/attributes/TypeAttributes.ts @@ -1,8 +1,8 @@ -import { mapFilterMap, mapFilter, mapTranspose, hashString } from "collection-utils"; +import { hashString, mapFilter, mapFilterMap, mapTranspose } from "collection-utils"; -import { panic, assert } from "../support/Support"; -import { type Type, type TypeKind } from "../Type"; import { type BaseGraphRewriteBuilder } from "../GraphRewriting"; +import { assert, panic } from "../support/Support"; +import { type Type, type TypeKind } from "../Type"; export class TypeAttributeKind { public constructor(public readonly name: string) {} diff --git a/packages/quicktype-core/src/attributes/TypeNames.ts b/packages/quicktype-core/src/attributes/TypeNames.ts index a1be97d07..f5d96a7ac 100644 --- a/packages/quicktype-core/src/attributes/TypeNames.ts +++ b/packages/quicktype-core/src/attributes/TypeNames.ts @@ -1,11 +1,11 @@ +import { definedMap, iterableFirst, iterableSkip, setMap, setUnionInto } from "collection-utils"; import * as pluralize from "pluralize"; -import { setMap, iterableFirst, iterableSkip, setUnionInto, definedMap } from "collection-utils"; -import { panic, defined, assert } from "../support/Support"; -import { type TypeAttributes } from "./TypeAttributes"; -import { TypeAttributeKind } from "./TypeAttributes"; -import { splitIntoWords } from "../support/Strings"; import { Chance } from "../support/Chance"; +import { splitIntoWords } from "../support/Strings"; +import { assert, defined, panic } from "../support/Support"; + +import { TypeAttributeKind, type TypeAttributes } from "./TypeAttributes"; let chance: Chance; let usedRandomNames: Set; diff --git a/packages/quicktype-core/src/attributes/URIAttributes.ts b/packages/quicktype-core/src/attributes/URIAttributes.ts index 78e2fcc68..f2b5cb560 100644 --- a/packages/quicktype-core/src/attributes/URIAttributes.ts +++ b/packages/quicktype-core/src/attributes/URIAttributes.ts @@ -1,13 +1,13 @@ +import { setUnionManyInto } from "collection-utils"; import URI from "urijs"; -import { type TypeAttributes } from "./TypeAttributes"; -import { TypeAttributeKind, emptyTypeAttributes } from "./TypeAttributes"; -import { setUnionManyInto } from "collection-utils"; -import { type JSONSchemaType, type JSONSchemaAttributes, type Ref } from "../input/JSONSchemaInput"; +import { type JSONSchemaAttributes, type JSONSchemaType, type Ref } from "../input/JSONSchemaInput"; import { type JSONSchema } from "../input/JSONSchemaStore"; import { checkArray, checkString } from "../support/Support"; import { type Type } from "../Type"; +import { TypeAttributeKind, type TypeAttributes, emptyTypeAttributes } from "./TypeAttributes"; + const protocolsSchemaProperty = "qt-uri-protocols"; const extensionsSchemaProperty = "qt-uri-extensions"; diff --git a/packages/quicktype-core/src/index.ts b/packages/quicktype-core/src/index.ts index a56413a31..41c968bdd 100644 --- a/packages/quicktype-core/src/index.ts +++ b/packages/quicktype-core/src/index.ts @@ -12,7 +12,7 @@ export { inferenceFlagsObject, type InferenceFlags, type InferenceFlagName, - type RunContext, + type RunContext } from "./Run"; export { CompressedJSON, type Value } from "./input/CompressedJSON"; export { type Input, InputData, JSONInput, type JSONSourceData, jsonInputForTargetLanguage } from "./input/Inputs"; @@ -29,7 +29,7 @@ export { type Annotation, modifySource, singleWord, - parenIfNeeded, + parenIfNeeded } from "./Source"; export { Name, funPrefixNamer, Namer } from "./Naming"; export { IssueAnnotationData } from "./Annotation"; @@ -41,7 +41,7 @@ export { parseJSON, checkStringMap, checkArray, - inflateBase64, + inflateBase64 } from "./support/Support"; export { splitIntoWords, @@ -50,7 +50,7 @@ export { firstUpperWordStyle, allUpperWordStyle, legalizeCharacters, - isLetterOrDigit, + isLetterOrDigit } from "./support/Strings"; export { train as trainMarkovChain } from "./MarkovChain"; export { QuickTypeError, messageError, messageAssert } from "./Messages"; @@ -66,10 +66,12 @@ export { type TypeKind, ObjectType, type TransformedStringTypeKind, - type PrimitiveStringTypeKind, + type PrimitiveStringTypeKind } from "./Type"; export { getStream } from "./input/io/get-stream"; +// eslint-disable-next-line import/no-cycle export { readableFromFileOrURL, readFromFileOrURL } from "./input/io/NodeIO"; +// eslint-disable-next-line import/no-cycle export { FetchingJSONSchemaStore } from "./input/FetchingJSONSchemaStore"; export { JSONSchemaStore, type JSONSchema } from "./input/JSONSchemaStore"; export { sourcesFromPostmanCollection } from "./input/PostmanCollection"; @@ -93,14 +95,14 @@ export { JavaScriptTargetLanguage, JavaScriptRenderer, javaScriptOptions } from export { JavaScriptPropTypesTargetLanguage, JavaScriptPropTypesRenderer, - javaScriptPropTypesOptions, + javaScriptPropTypesOptions } from "./language/JavaScriptPropTypes"; export { TypeScriptTargetLanguage, TypeScriptRenderer, FlowTargetLanguage, FlowRenderer, - tsFlowOptions, + tsFlowOptions } from "./language/TypeScriptFlow"; export { SwiftTargetLanguage, SwiftRenderer, swiftOptions } from "./language/Swift"; export { KotlinTargetLanguage, KotlinRenderer, kotlinOptions } from "./language/Kotlin"; diff --git a/packages/quicktype-core/src/input/CompressedJSON.ts b/packages/quicktype-core/src/input/CompressedJSON.ts index cb3909e0d..2aa3355cf 100644 --- a/packages/quicktype-core/src/input/CompressedJSON.ts +++ b/packages/quicktype-core/src/input/CompressedJSON.ts @@ -1,10 +1,13 @@ import { addHashCode, hashCodeInit, hashString } from "collection-utils"; -import { defined, panic, assert } from "../support/Support"; -import { type TransformedStringTypeKind } from "../Type"; -import { isPrimitiveStringTypeKind, transformedStringTypeTargetTypeKindsMap } from "../Type"; -import { type DateTimeRecognizer } from "../DateTime"; import { inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; +import { type DateTimeRecognizer } from "../DateTime"; +import { assert, defined, panic } from "../support/Support"; +import { + type TransformedStringTypeKind, + isPrimitiveStringTypeKind, + transformedStringTypeTargetTypeKindsMap +} from "../Type"; export enum Tag { Null = 1, diff --git a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts index edd9a8824..4e7c132f5 100644 --- a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts @@ -1,7 +1,8 @@ -import { type JSONSchema } from "./JSONSchemaStore"; -import { JSONSchemaStore } from "./JSONSchemaStore"; +// eslint-disable-next-line import/no-cycle import { parseJSON } from ".."; + import { readFromFileOrURL } from "./io/NodeIO"; +import { type JSONSchema, JSONSchemaStore } from "./JSONSchemaStore"; export class FetchingJSONSchemaStore extends JSONSchemaStore { public constructor(private readonly _httpHeaders?: string[]) { diff --git a/packages/quicktype-core/src/input/Inference.ts b/packages/quicktype-core/src/input/Inference.ts index 07c1c52d3..a8dc6a772 100644 --- a/packages/quicktype-core/src/input/Inference.ts +++ b/packages/quicktype-core/src/input/Inference.ts @@ -1,17 +1,21 @@ -import { type Value, type CompressedJSON } from "./CompressedJSON"; -import { Tag, valueTag } from "./CompressedJSON"; -import { assertNever, defined, panic, assert } from "../support/Support"; -import { type TypeBuilder } from "../TypeBuilder"; -import { UnionBuilder, UnionAccumulator } from "../UnionBuilder"; -import { type ClassProperty } from "../Type"; -import { transformedStringTypeTargetTypeKindsMap, UnionType, ClassType, MapType, ArrayType } from "../Type"; -import { type TypeAttributes } from "../attributes/TypeAttributes"; -import { emptyTypeAttributes } from "../attributes/TypeAttributes"; import { StringTypes, inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; -import { type TypeRef } from "../TypeGraph"; -import { derefTypeRef } from "../TypeGraph"; +import { type TypeAttributes, emptyTypeAttributes } from "../attributes/TypeAttributes"; import { messageError } from "../Messages"; +import { assert, assertNever, defined, panic } from "../support/Support"; +import { + ArrayType, + type ClassProperty, + ClassType, + MapType, + UnionType, + transformedStringTypeTargetTypeKindsMap +} from "../Type"; +import { type TypeBuilder } from "../TypeBuilder"; +import { type TypeRef, derefTypeRef } from "../TypeGraph"; import { nullableFromUnion } from "../TypeUtils"; +import { UnionAccumulator, UnionBuilder } from "../UnionBuilder"; + +import { type CompressedJSON, Tag, type Value, valueTag } from "./CompressedJSON"; // This should be the recursive type // Value[] | NestedValueArray[] diff --git a/packages/quicktype-core/src/input/Inputs.ts b/packages/quicktype-core/src/input/Inputs.ts index 5f57ac684..031d84ead 100644 --- a/packages/quicktype-core/src/input/Inputs.ts +++ b/packages/quicktype-core/src/input/Inputs.ts @@ -1,16 +1,17 @@ -import { iterableFirst, iterableFind, iterableSome, setFilterMap, withDefault, arrayMapSync } from "collection-utils"; +import { arrayMapSync, iterableFind, iterableFirst, iterableSome, setFilterMap, withDefault } from "collection-utils"; -import { type Value, type CompressedJSON } from "./CompressedJSON"; -import { CompressedJSONFromString } from "./CompressedJSON"; -import { panic, errorMessage, defined } from "../support/Support"; +import { descriptionTypeAttributeKind } from "../attributes/Description"; +import { makeNamesTypeAttributes } from "../attributes/TypeNames"; +// eslint-disable-next-line import/no-cycle +import { languageNamed } from "../language/All"; import { messageError } from "../Messages"; +import { type RunContext } from "../Run"; +import { defined, errorMessage, panic } from "../support/Support"; +import { type TargetLanguage } from "../TargetLanguage"; import { type TypeBuilder } from "../TypeBuilder"; -import { makeNamesTypeAttributes } from "../attributes/TypeNames"; -import { descriptionTypeAttributeKind } from "../attributes/Description"; + +import { type CompressedJSON, CompressedJSONFromString, type Value } from "./CompressedJSON"; import { TypeInference } from "./Inference"; -import { type TargetLanguage } from "../TargetLanguage"; -import { type RunContext } from "../Run"; -import { languageNamed } from "../language/All"; export interface Input { addSource: (source: T) => Promise; diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index c0aa1c1b8..03ce2ea6c 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -1,54 +1,62 @@ -import URI from "urijs"; import { - setFilter, EqualityMap, - mapMap, - mapFromObject, - setSubtract, - mapFromIterable, - iterableFind, - mapSortBy, - mapMapSync, - mapMergeInto, - arrayMapSync, - arrayLast, + addHashCode, arrayGetFromEnd, - hashCodeOf, - hasOwnProperty, + arrayLast, + arrayMapSync, definedMap, - addHashCode, + // eslint-disable-next-line @typescript-eslint/no-redeclare + hasOwnProperty, + hashCodeOf, + hashString, + iterableFind, iterableFirst, - hashString + mapFromIterable, + mapFromObject, + mapMap, + mapMapSync, + mapMergeInto, + mapSortBy, + setFilter, + setSubtract } from "collection-utils"; +import URI from "urijs"; -import { type PrimitiveTypeKind, type TransformedStringTypeKind } from "../Type"; -import { transformedStringTypeTargetTypeKindsMap, isNumberTypeKind } from "../Type"; -import { type StringMap } from "../support/Support"; -import { panic, assertNever, assert, defined, parseJSON } from "../support/Support"; -import { type TypeBuilder } from "../TypeBuilder"; -import { TypeNames } from "../attributes/TypeNames"; -import { makeNamesTypeAttributes, modifyTypeNames, singularizeTypeNames } from "../attributes/TypeNames"; -import { type TypeAttributes } from "../attributes/TypeAttributes"; -import { makeTypeAttributesInferred, emptyTypeAttributes, combineTypeAttributes } from "../attributes/TypeAttributes"; -import { type JSONSchema } from "./JSONSchemaStore"; -import { JSONSchemaStore } from "./JSONSchemaStore"; -import { messageAssert, messageError } from "../Messages"; +import { accessorNamesAttributeProducer } from "../attributes/AccessorNames"; +import { + minMaxAttributeProducer, + minMaxLengthAttributeProducer, + patternAttributeProducer +} from "../attributes/Constraints"; +// eslint-disable-next-line import/no-cycle +import { descriptionAttributeProducer } from "../attributes/Description"; +import { enumValuesAttributeProducer } from "../attributes/EnumValues"; import { StringTypes } from "../attributes/StringTypes"; - -import { type TypeRef } from "../TypeGraph"; +import { + type TypeAttributes, + combineTypeAttributes, + emptyTypeAttributes, + makeTypeAttributesInferred +} from "../attributes/TypeAttributes"; +import { TypeNames, makeNamesTypeAttributes, modifyTypeNames, singularizeTypeNames } from "../attributes/TypeNames"; +import { uriSchemaAttributesProducer } from "../attributes/URIAttributes"; +import { messageAssert, messageError } from "../Messages"; import { type RunContext } from "../Run"; +import { type StringMap, assert, assertNever, defined, panic, parseJSON } from "../support/Support"; +import { + type PrimitiveTypeKind, + type TransformedStringTypeKind, + isNumberTypeKind, + transformedStringTypeTargetTypeKindsMap +} from "../Type"; +import { type TypeBuilder } from "../TypeBuilder"; +import { type TypeRef } from "../TypeGraph"; + import { type Input } from "./Inputs"; +import { type JSONSchema, JSONSchemaStore } from "./JSONSchemaStore"; // There's a cyclic import here. Ignoring now because it requires a large refactor. // skipcq: JS-E1008 -import { descriptionAttributeProducer } from "../attributes/Description"; - -import { accessorNamesAttributeProducer } from "../attributes/AccessorNames"; -import { enumValuesAttributeProducer } from "../attributes/EnumValues"; -import { minMaxAttributeProducer } from "../attributes/Constraints"; -import { minMaxLengthAttributeProducer } from "../attributes/Constraints"; -import { patternAttributeProducer } from "../attributes/Constraints"; -import { uriSchemaAttributesProducer } from "../attributes/URIAttributes"; export enum PathElementKind { Root = 1, diff --git a/packages/quicktype-core/src/input/JSONSchemaStore.ts b/packages/quicktype-core/src/input/JSONSchemaStore.ts index 9fe5c62ec..4292bf08c 100644 --- a/packages/quicktype-core/src/input/JSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/JSONSchemaStore.ts @@ -1,5 +1,4 @@ -import { type StringMap } from "../support/Support"; -import { assert } from "../support/Support"; +import { type StringMap, assert } from "../support/Support"; export type JSONSchema = StringMap | boolean; diff --git a/packages/quicktype-core/src/input/PostmanCollection.ts b/packages/quicktype-core/src/input/PostmanCollection.ts index 7d4a4b7b2..ce554ffb5 100644 --- a/packages/quicktype-core/src/input/PostmanCollection.ts +++ b/packages/quicktype-core/src/input/PostmanCollection.ts @@ -1,4 +1,5 @@ import { parseJSON } from "../support/Support"; + import { type JSONSourceData } from "./Inputs"; function isValidJSON (s: string): boolean { diff --git a/packages/quicktype-core/src/input/io/NodeIO.ts b/packages/quicktype-core/src/input/io/NodeIO.ts index fdc63b6b5..e310087b7 100644 --- a/packages/quicktype-core/src/input/io/NodeIO.ts +++ b/packages/quicktype-core/src/input/io/NodeIO.ts @@ -1,12 +1,15 @@ import * as fs from "fs"; -import { type Readable } from "readable-stream"; -import { isNode } from "browser-or-node"; -import { getStream } from "./get-stream"; + import { defined, exceptionToString } from "@glideapps/ts-necessities"; +import { isNode } from "browser-or-node"; +import fetch from "cross-fetch"; +import isURL from "is-url"; +import { type Readable } from "readable-stream"; + +// eslint-disable-next-line import/no-cycle import { messageError, panic } from "../../index"; -import isURL from "is-url"; -import fetch from "cross-fetch"; +import { getStream } from "./get-stream"; interface HttpHeaders { [key: string]: string; diff --git a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts index 16ea64a20..063f2794e 100644 --- a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts +++ b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts @@ -1,6 +1,7 @@ -import { type Options } from "."; import { PassThrough } from "readable-stream"; +import { type Options } from "."; + export default function bufferStream(opts: Options) { opts = Object.assign({}, opts); diff --git a/packages/quicktype-core/src/input/io/get-stream/index.ts b/packages/quicktype-core/src/input/io/get-stream/index.ts index d8d067cae..4ae2d3ae7 100644 --- a/packages/quicktype-core/src/input/io/get-stream/index.ts +++ b/packages/quicktype-core/src/input/io/get-stream/index.ts @@ -1,4 +1,5 @@ import { type Readable } from "readable-stream"; + import bufferStream from "./buffer-stream"; export interface Options { diff --git a/packages/quicktype-core/src/language/All.ts b/packages/quicktype-core/src/language/All.ts index 91cb4b1a0..ee6648e59 100644 --- a/packages/quicktype-core/src/language/All.ts +++ b/packages/quicktype-core/src/language/All.ts @@ -2,31 +2,32 @@ import { iterableFind } from "collection-utils"; import { type TargetLanguage } from "../TargetLanguage"; -import { CSharpTargetLanguage } from "./CSharp"; -import { GoTargetLanguage } from "./Golang"; import { CJSONTargetLanguage } from "./CJSON"; import { CPlusPlusTargetLanguage } from "./CPlusPlus"; -import { ObjectiveCTargetLanguage } from "./Objective-C"; +import { CrystalTargetLanguage } from "./Crystal"; +import { CSharpTargetLanguage } from "./CSharp"; +import { DartTargetLanguage } from "./Dart"; +import { ElmTargetLanguage } from "./Elm"; +import { GoTargetLanguage } from "./Golang"; +import { HaskellTargetLanguage } from "./Haskell"; import { JavaTargetLanguage } from "./Java"; import { JavaScriptTargetLanguage } from "./JavaScript"; +// eslint-disable-next-line import/no-cycle import { JavaScriptPropTypesTargetLanguage } from "./JavaScriptPropTypes"; -import { TypeScriptTargetLanguage, FlowTargetLanguage } from "./TypeScriptFlow"; -import { SwiftTargetLanguage } from "./Swift"; +import { JSONSchemaTargetLanguage } from "./JSONSchema"; import { KotlinTargetLanguage } from "./Kotlin"; +import { ObjectiveCTargetLanguage } from "./Objective-C"; +import { PhpTargetLanguage } from "./Php"; +import { PikeTargetLanguage } from "./Pike"; +import { PythonTargetLanguage } from "./Python"; +import { RubyTargetLanguage } from "./ruby"; +import { RustTargetLanguage } from "./Rust"; import { Scala3TargetLanguage } from "./Scala3"; import { SmithyTargetLanguage } from "./Smithy4s"; -import { ElmTargetLanguage } from "./Elm"; -import { JSONSchemaTargetLanguage } from "./JSONSchema"; -import { RustTargetLanguage } from "./Rust"; -import { CrystalTargetLanguage } from "./Crystal"; -import { RubyTargetLanguage } from "./ruby"; -import { DartTargetLanguage } from "./Dart"; -import { PythonTargetLanguage } from "./Python"; -import { PikeTargetLanguage } from "./Pike"; -import { HaskellTargetLanguage } from "./Haskell"; -import { TypeScriptZodTargetLanguage } from "./TypeScriptZod"; -import { PhpTargetLanguage } from "./Php"; +import { SwiftTargetLanguage } from "./Swift"; import { TypeScriptEffectSchemaTargetLanguage } from "./TypeScriptEffectSchema"; +import { FlowTargetLanguage, TypeScriptTargetLanguage } from "./TypeScriptFlow"; +import { TypeScriptZodTargetLanguage } from "./TypeScriptZod"; export const all: TargetLanguage[] = [ new CSharpTargetLanguage(), @@ -54,18 +55,15 @@ export const all: TargetLanguage[] = [ new HaskellTargetLanguage(), new TypeScriptZodTargetLanguage(), new TypeScriptEffectSchemaTargetLanguage(), - new PhpTargetLanguage(), + new PhpTargetLanguage() ]; -export function languageNamed (name: string, targetLanguages?: TargetLanguage[]): TargetLanguage | undefined { +export function languageNamed(name: string, targetLanguages?: TargetLanguage[]): TargetLanguage | undefined { if (targetLanguages === undefined) { targetLanguages = all; } - const maybeTargetLanguage = iterableFind( - targetLanguages, - l => l.names.includes(name) || l.displayName === name, - ); + const maybeTargetLanguage = iterableFind(targetLanguages, l => l.names.includes(name) || l.displayName === name); if (maybeTargetLanguage !== undefined) return maybeTargetLanguage; return iterableFind(targetLanguages, l => l.extension === name); } diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index 84d1c41eb..0bfd40f57 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -22,30 +22,25 @@ */ /* Imports */ -import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type TypeKind } from "../Type"; -import { ClassType, ArrayType, MapType, EnumType, UnionType } from "../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type NameStyle, type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; +import { getAccessorName } from "../attributes/AccessorNames"; +import { enumCaseValues } from "../attributes/EnumValues"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type NameStyle, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; import { type Sourcelike } from "../Source"; -import { type NamingStyle } from "../support/Strings"; import { + type NamingStyle, allUpperWordStyle, - legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit, + legalizeCharacters, makeNameStyle } from "../support/Strings"; -import { defined, assertNever, panic, numberEnumValues } from "../support/Support"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { assert } from "../support/Support"; -import { type RenderContext } from "../Renderer"; -import { getAccessorName } from "../attributes/AccessorNames"; -import { enumCaseValues } from "../attributes/EnumValues"; +import { assert, assertNever, defined, numberEnumValues, panic } from "../support/Support"; +import { TargetLanguage } from "../TargetLanguage"; +import { ArrayType, ClassType, EnumType, MapType, type Type, type TypeKind, UnionType } from "../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; /* Naming styles */ const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; diff --git a/packages/quicktype-core/src/language/CPlusPlus.ts b/packages/quicktype-core/src/language/CPlusPlus.ts index f5ec4f5f0..b75f834f6 100644 --- a/packages/quicktype-core/src/language/CPlusPlus.ts +++ b/packages/quicktype-core/src/language/CPlusPlus.ts @@ -1,42 +1,56 @@ import { - setUnion, arrayIntercalate, - toReadonlyArray, - iterableFirst, iterableFind, + iterableFirst, iterableSome, + setUnion, + toReadonlyArray, withDefault } from "collection-utils"; -import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type TypeKind, type ClassProperty } from "../Type"; -import { ClassType, ArrayType, MapType, EnumType, UnionType } from "../Type"; -import { nullableFromUnion, matchType, removeNullFromUnion, isNamedType, directlyReachableTypes } from "../TypeUtils"; -import { type NameStyle, type Name, type Namer } from "../Naming"; -import { funPrefixNamer, DependencyName } from "../Naming"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type NamingStyle } from "../support/Strings"; +import { getAccessorName } from "../attributes/AccessorNames"; import { - legalizeCharacters, + type MinMaxConstraint, + minMaxLengthForType, + minMaxValueForType, + patternForType +} from "../attributes/Constraints"; +import { enumCaseValues } from "../attributes/EnumValues"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Declaration } from "../DeclarationIR"; +import { DependencyName, type Name, type NameStyle, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../Source"; +import { + type NamingStyle, isAscii, isLetterOrUnderscoreOrDigit, - stringEscape, - makeNameStyle + legalizeCharacters, + makeNameStyle, + stringEscape } from "../support/Strings"; -import { defined, assertNever, panic, numberEnumValues } from "../support/Support"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { StringOption, EnumOption, BooleanOption, getOptionValues } from "../RendererOptions"; -import { assert } from "../support/Support"; -import { type Declaration } from "../DeclarationIR"; -import { type RenderContext } from "../Renderer"; -import { getAccessorName } from "../attributes/AccessorNames"; -import { enumCaseValues } from "../attributes/EnumValues"; -import { type MinMaxConstraint } from "../attributes/Constraints"; -import { minMaxValueForType, minMaxLengthForType, patternForType } from "../attributes/Constraints"; +import { assert, assertNever, defined, numberEnumValues, panic } from "../support/Support"; +import { TargetLanguage } from "../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + MapType, + type Type, + type TypeKind, + UnionType +} from "../Type"; +import { directlyReachableTypes, isNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; const underscoreValue: [string, NamingStyle] = ["underscore-case", "underscore"]; @@ -164,12 +178,12 @@ export class CPlusPlusTargetLanguage extends TargetLanguage { } function constraintsForType(t: Type): - | { - minMax?: MinMaxConstraint; - minMaxLength?: MinMaxConstraint; - pattern?: string; - } - | undefined { +| { + minMax?: MinMaxConstraint; + minMaxLength?: MinMaxConstraint; + pattern?: string; +} +| undefined { const minMax = minMaxValueForType(t); const minMaxLength = minMaxLengthForType(t); const pattern = patternForType(t); @@ -1361,11 +1375,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { pattern === undefined ? this._nulloptType : [ - this._stringType.getType(), - "(", - this._stringType.createStringLiteral([stringEscape(pattern)]), - ")" - ], + this._stringType.getType(), + "(", + this._stringType.createStringLiteral([stringEscape(pattern)]), + ")" + ], ")" ]); }); diff --git a/packages/quicktype-core/src/language/CSharp.ts b/packages/quicktype-core/src/language/CSharp.ts index f87193182..54c0de48d 100644 --- a/packages/quicktype-core/src/language/CSharp.ts +++ b/packages/quicktype-core/src/language/CSharp.ts @@ -1,57 +1,64 @@ import { arrayIntercalate } from "collection-utils"; +import unicode from "unicode-properties"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; +import { minMaxLengthForType, minMaxValueForType } from "../attributes/Constraints"; +import { ConvenienceRenderer, type ForbiddenWordsInfo, inferredNameOrder } from "../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, SimpleName, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; import { - type Type, - type ClassProperty, - type TransformedStringTypeKind, - type PrimitiveStringTypeKind, - type PrimitiveType -} from "../Type"; -import { EnumType, UnionType, ClassType, ArrayType } from "../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion, directlyReachableSingleNamedType } from "../TypeUtils"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated, modifySource } from "../Source"; -import { type WordInName } from "../support/Strings"; + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; import { - utf16LegalizeCharacters, - utf16StringEscape, - splitIntoWords, + type WordInName, + camelCase, combineWords, firstUpperWordStyle, - camelCase + splitIntoWords, + utf16LegalizeCharacters, + utf16StringEscape } from "../support/Strings"; -import { defined, assert, panic, assertNever } from "../support/Support"; -import { type Name, type Namer } from "../Naming"; -import { DependencyName, funPrefixNamer, SimpleName } from "../Naming"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer, inferredNameOrder } from "../ConvenienceRenderer"; +import { assert, assertNever, defined, panic } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { StringOption, EnumOption, BooleanOption, getOptionValues } from "../RendererOptions"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type Transformer, type Transformation } from "../Transformers"; import { - followTargetType, - transformationForType, - DecodingTransformer, - DecodingChoiceTransformer, - UnionInstantiationTransformer, + ArrayDecodingTransformer, + ArrayEncodingTransformer, ChoiceTransformer, - UnionMemberMatchTransformer, + DecodingChoiceTransformer, + DecodingTransformer, EncodingTransformer, + MinMaxLengthCheckTransformer, + MinMaxValueTransformer, + ParseStringTransformer, StringMatchTransformer, StringProducerTransformer, - ParseStringTransformer, StringifyTransformer, - ArrayDecodingTransformer, - ArrayEncodingTransformer, - MinMaxLengthCheckTransformer, - MinMaxValueTransformer + type Transformation, + type Transformer, + UnionInstantiationTransformer, + UnionMemberMatchTransformer, + followTargetType, + transformationForType } from "../Transformers"; -import { type RenderContext } from "../Renderer"; -import { minMaxLengthForType, minMaxValueForType } from "../attributes/Constraints"; -import unicode from "unicode-properties"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + type PrimitiveStringTypeKind, + type PrimitiveType, + type TransformedStringTypeKind, + type Type, + UnionType +} from "../Type"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export enum Framework { Newtonsoft = "Newtonsoft", diff --git a/packages/quicktype-core/src/language/Crystal.ts b/packages/quicktype-core/src/language/Crystal.ts index 05708f30a..1376c488c 100644 --- a/packages/quicktype-core/src/language/Crystal.ts +++ b/packages/quicktype-core/src/language/Crystal.ts @@ -1,29 +1,26 @@ -import { TargetLanguage } from "../TargetLanguage"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { type Option } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../Source"; import { - legalizeCharacters, - splitIntoWords, - isLetterOrUnderscoreOrDigit, - combineWords, allLowerWordStyle, + combineWords, + escapeNonPrintableMapper, firstUpperWordStyle, intToHex, - utf32ConcatMap, - escapeNonPrintableMapper, - isPrintable, isAscii, - isLetterOrUnderscore + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap } from "../support/Strings"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type UnionType, type Type, type ClassType, type EnumType } from "../Type"; +import { TargetLanguage } from "../TargetLanguage"; +import { type ClassType, type EnumType, type Type, type UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated } from "../Source"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type Option } from "../RendererOptions"; -import { type RenderContext } from "../Renderer"; export class CrystalTargetLanguage extends TargetLanguage { protected makeRenderer(renderContext: RenderContext): CrystalRenderer { diff --git a/packages/quicktype-core/src/language/Dart.ts b/packages/quicktype-core/src/language/Dart.ts index a30e797a1..71360e7d1 100644 --- a/packages/quicktype-core/src/language/Dart.ts +++ b/packages/quicktype-core/src/language/Dart.ts @@ -1,15 +1,9 @@ -import { - type ClassProperty, - type ClassType, - type PrimitiveStringTypeKind, - type TransformedStringTypeKind, - type Type, - type UnionType -} from "../Type"; -import { EnumType } from "../Type"; -import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated, modifySource } from "../Source"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { BooleanOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; import { allLowerWordStyle, allUpperWordStyle, @@ -27,19 +21,19 @@ import { utf16ConcatMap, utf16LegalizeCharacters } from "../support/Strings"; - -import { type StringTypeMapping } from "../TypeBuilder"; - -import { type Name, type Namer } from "../Naming"; -import { DependencyName, funPrefixNamer } from "../Naming"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, getOptionValues, StringOption } from "../RendererOptions"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { defined } from "../support/Support"; -import { type RenderContext } from "../Renderer"; +import { TargetLanguage } from "../TargetLanguage"; +import { + type ClassProperty, + type ClassType, + EnumType, + type PrimitiveStringTypeKind, + type TransformedStringTypeKind, + type Type, + type UnionType +} from "../Type"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; export const dartOptions = { nullSafety: new BooleanOption("null-safety", "Null Safety", true), @@ -204,8 +198,8 @@ function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, origin const firstWordStyle = upperUnderscore ? allUpperWordStyle : startWithUpper - ? firstUpperWordStyle - : allLowerWordStyle; + ? firstUpperWordStyle + : allLowerWordStyle; const restWordStyle = upperUnderscore ? allUpperWordStyle : firstUpperWordStyle; return combineWords( words, diff --git a/packages/quicktype-core/src/language/Elm.ts b/packages/quicktype-core/src/language/Elm.ts index a9c81776e..426764b63 100644 --- a/packages/quicktype-core/src/language/Elm.ts +++ b/packages/quicktype-core/src/language/Elm.ts @@ -1,33 +1,35 @@ -import { mapContains, arrayIntercalate } from "collection-utils"; +import { arrayIntercalate, mapContains } from "collection-utils"; -import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { EnumOption, StringOption, BooleanOption, getOptionValues } from "../RendererOptions"; -import { type Type, type ClassType, type EnumType, type ClassProperty } from "../Type"; -import { UnionType } from "../Type"; -import { matchType, nullableFromUnion } from "../TypeUtils"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Namer, type Name } from "../Naming"; -import { DependencyName, funPrefixNamer } from "../Naming"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; import { - legalizeCharacters, - isLetterOrUnderscoreOrDigit, - isLetterOrUnderscore, + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../RendererOptions"; +import { type MultiWord, type Sourcelike, annotated, multiWord, parenIfNeeded, singleWord } from "../Source"; +import { + allLowerWordStyle, + allUpperWordStyle, + combineWords, decapitalize, - stringEscape, + firstUpperWordStyle, isAscii, + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + legalizeCharacters, splitIntoWords, - combineWords, - firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle + stringEscape } from "../support/Strings"; import { defined } from "../support/Support"; -import { type Sourcelike, type MultiWord } from "../Source"; -import { annotated, singleWord, multiWord, parenIfNeeded } from "../Source"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type RenderContext } from "../Renderer"; +import { TargetLanguage } from "../TargetLanguage"; +import { type ClassProperty, type ClassType, type EnumType, type Type, UnionType } from "../Type"; +import { matchType, nullableFromUnion } from "../TypeUtils"; export const elmOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), diff --git a/packages/quicktype-core/src/language/Golang.ts b/packages/quicktype-core/src/language/Golang.ts index 0dd4afcb5..277c083f5 100644 --- a/packages/quicktype-core/src/language/Golang.ts +++ b/packages/quicktype-core/src/language/Golang.ts @@ -1,29 +1,25 @@ -import { type TypeKind, type Type, type ClassType, type EnumType, type ClassProperty } from "../Type"; -import { UnionType } from "../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Name, type Namer } from "../Naming"; -import { DependencyName, funPrefixNamer } from "../Naming"; +import { type PrimitiveStringTypeKind, type StringTypeMapping, type TransformedStringTypeKind } from ".."; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { BooleanOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; import { - legalizeCharacters, + allUpperWordStyle, + camelCase, + combineWords, + firstUpperWordStyle, isLetterOrUnderscore, isLetterOrUnderscoreOrDigit, - stringEscape, + legalizeCharacters, splitIntoWords, - combineWords, - firstUpperWordStyle, - allUpperWordStyle, - camelCase + stringEscape } from "../support/Strings"; import { assert, defined } from "../support/Support"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { StringOption, BooleanOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated, modifySource } from "../Source"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; import { TargetLanguage } from "../TargetLanguage"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type RenderContext } from "../Renderer"; -import { type StringTypeMapping, type TransformedStringTypeKind, type PrimitiveStringTypeKind } from ".."; +import { type ClassProperty, type ClassType, type EnumType, type Type, type TypeKind, UnionType } from "../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export const goOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), diff --git a/packages/quicktype-core/src/language/Haskell.ts b/packages/quicktype-core/src/language/Haskell.ts index f33ce9927..7b7b7ef49 100644 --- a/packages/quicktype-core/src/language/Haskell.ts +++ b/packages/quicktype-core/src/language/Haskell.ts @@ -1,28 +1,32 @@ import { mapContains } from "collection-utils"; -import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { EnumOption, StringOption, BooleanOption, getOptionValues } from "../RendererOptions"; -import { type Type, type ClassType, type UnionType, type EnumType, type ClassProperty } from "../Type"; -import { matchType, nullableFromUnion } from "../TypeUtils"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Namer, type Name } from "../Naming"; -import { funPrefixNamer } from "../Naming"; + +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; import { - legalizeCharacters, - isLetterOrUnderscoreOrDigit, - isLetterOrUnderscore, - stringEscape, - isAscii, - splitIntoWords, + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../RendererOptions"; +import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../Source"; +import { + allLowerWordStyle, + allUpperWordStyle, combineWords, firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle + isAscii, + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + legalizeCharacters, + splitIntoWords, + stringEscape } from "../support/Strings"; -import { type Sourcelike, type MultiWord } from "../Source"; -import { singleWord, multiWord, parenIfNeeded } from "../Source"; -import { type RenderContext } from "../Renderer"; +import { TargetLanguage } from "../TargetLanguage"; +import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../Type"; +import { matchType, nullableFromUnion } from "../TypeUtils"; export const haskellOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), diff --git a/packages/quicktype-core/src/language/JSONSchema.ts b/packages/quicktype-core/src/language/JSONSchema.ts index 612bd7310..ab7e85b1e 100644 --- a/packages/quicktype-core/src/language/JSONSchema.ts +++ b/packages/quicktype-core/src/language/JSONSchema.ts @@ -1,25 +1,28 @@ -import { mapFirst, iterableFirst } from "collection-utils"; +import { iterableFirst, mapFirst } from "collection-utils"; -import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type UnionType, type EnumType, type ObjectType } from "../Type"; -import { transformedStringTypeTargetTypeKindsMap } from "../Type"; -import { matchTypeExhaustive } from "../TypeUtils"; +import { addDescriptionToSchema } from "../attributes/Description"; import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Namer, type Name } from "../Naming"; -import { funPrefixNamer } from "../Naming"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { type Option } from "../RendererOptions"; import { - legalizeCharacters, - splitIntoWords, + allUpperWordStyle, combineWords, firstUpperWordStyle, - allUpperWordStyle + legalizeCharacters, + splitIntoWords } from "../support/Strings"; import { defined, panic } from "../support/Support"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { getNoStringTypeMapping } from "../TypeBuilder"; -import { addDescriptionToSchema } from "../attributes/Description"; -import { type Option } from "../RendererOptions"; -import { type RenderContext } from "../Renderer"; +import { TargetLanguage } from "../TargetLanguage"; +import { + type EnumType, + type ObjectType, + type Type, + type UnionType, + transformedStringTypeTargetTypeKindsMap +} from "../Type"; +import { type StringTypeMapping, getNoStringTypeMapping } from "../TypeBuilder"; +import { matchTypeExhaustive } from "../TypeUtils"; export class JSONSchemaTargetLanguage extends TargetLanguage { public constructor() { diff --git a/packages/quicktype-core/src/language/Java.ts b/packages/quicktype-core/src/language/Java.ts index 25b975ad2..7080be5e9 100644 --- a/packages/quicktype-core/src/language/Java.ts +++ b/packages/quicktype-core/src/language/Java.ts @@ -1,14 +1,18 @@ +import { type PrimitiveStringTypeKind, type StringTypeMapping, type TransformedStringTypeKind } from ".."; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { DependencyName, funPrefixNamer } from "../Naming"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, EnumOption, getOptionValues, StringOption } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated } from "../Source"; -import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; +import { + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../Source"; +import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; import { allLowerWordStyle, allUpperWordStyle, @@ -26,10 +30,17 @@ import { } from "../support/Strings"; import { assert, assertNever, defined, panic } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type Type, type TypeKind } from "../Type"; -import { ArrayType, ClassType, EnumType, MapType, UnionType } from "../Type"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + MapType, + type Type, + type TypeKind, + UnionType +} from "../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type StringTypeMapping, type TransformedStringTypeKind, type PrimitiveStringTypeKind } from ".."; export const javaOptions = { useList: new EnumOption( diff --git a/packages/quicktype-core/src/language/JavaScript.ts b/packages/quicktype-core/src/language/JavaScript.ts index 5b1b1b7c8..0cf29f4ff 100644 --- a/packages/quicktype-core/src/language/JavaScript.ts +++ b/packages/quicktype-core/src/language/JavaScript.ts @@ -1,39 +1,35 @@ import { arrayIntercalate } from "collection-utils"; +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { BooleanOption, EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, modifySource } from "../Source"; +import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; +import { ConvertersOptions, convertersOption } from "../support/Converters"; import { - type TransformedStringTypeKind, - type PrimitiveStringTypeKind, - type Type, - type ClassProperty, - type ClassType, - type ObjectType -} from "../Type"; -import { matchType, directlyReachableSingleNamedType } from "../TypeUtils"; -import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; -import { convertersOption, ConvertersOptions } from "../support/Converters"; - -import { - utf16LegalizeCharacters, - utf16StringEscape, - splitIntoWords, + allLowerWordStyle, + camelCase, capitalize, combineWords, firstUpperWordStyle, - camelCase, - allLowerWordStyle + splitIntoWords, + utf16LegalizeCharacters, + utf16StringEscape } from "../support/Strings"; import { panic } from "../support/Support"; - -import { type Sourcelike } from "../Source"; -import { modifySource } from "../Source"; -import { type Namer, type Name } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; import { TargetLanguage } from "../TargetLanguage"; +import { + type ClassProperty, + type ClassType, + type ObjectType, + type PrimitiveStringTypeKind, + type TransformedStringTypeKind, + type Type +} from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, getOptionValues, EnumOption } from "../RendererOptions"; -import { type RenderContext } from "../Renderer"; +import { directlyReachableSingleNamedType, matchType } from "../TypeUtils"; + import { isES3IdentifierPart, isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; export const javaScriptOptions = { diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts index 3b9348f0b..cbdd4e6ad 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts @@ -1,20 +1,27 @@ -import { TargetLanguage } from "../TargetLanguage"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { getOptionValues, EnumOption } from "../RendererOptions"; -import { type RenderContext } from "../Renderer"; +import { panic } from "@glideapps/ts-necessities"; +import { arrayIntercalate } from "collection-utils"; + import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; -import { type ClassProperty, type ClassType, type ObjectType, type Sourcelike, type Type } from ".."; -import { capitalize, combineWords, firstUpperWordStyle, matchType, panic, splitIntoWords } from ".."; -import { allLowerWordStyle, utf16StringEscape } from "../support/Strings"; -import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; -import { legalizeName } from "./JavaScript"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; +import { type Sourcelike } from "../Source"; +import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; import { convertersOption } from "../support/Converters"; -import { directlyReachableSingleNamedType } from "../TypeUtils"; -import { arrayIntercalate } from "collection-utils"; -import { PrimitiveType } from "../Type"; +import { + allLowerWordStyle, + capitalize, + combineWords, + firstUpperWordStyle, + splitIntoWords, + utf16StringEscape +} from "../support/Strings"; +import { TargetLanguage } from "../TargetLanguage"; +import { type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type } from "../Type"; +import { directlyReachableSingleNamedType, matchType } from "../TypeUtils"; + +import { legalizeName } from "./JavaScript"; +import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; export const javaScriptPropTypesOptions = { acronymStyle: acronymOption(AcronymStyleOptions.Pascal), diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts index b2f46b466..f6fcebb04 100644 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ b/packages/quicktype-core/src/language/Kotlin.ts @@ -1,14 +1,12 @@ -import { iterableSome, arrayIntercalate } from "collection-utils"; +import { arrayIntercalate, iterableSome } from "collection-utils"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated, modifySource } from "../Source"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; +import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; import { allLowerWordStyle, allUpperWordStyle, @@ -27,11 +25,18 @@ import { } from "../support/Strings"; import { assertNever, mustNotHappen } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type EnumType, type ObjectType, type PrimitiveType, type Type } from "../Type"; -import { ArrayType, ClassType, MapType, UnionType } from "../Type"; +import { + ArrayType, + type ClassProperty, + ClassType, + type EnumType, + MapType, + type ObjectType, + type PrimitiveType, + type Type, + UnionType +} from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type RenderContext } from "../Renderer"; -import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; export enum Framework { None = "None", diff --git a/packages/quicktype-core/src/language/Objective-C.ts b/packages/quicktype-core/src/language/Objective-C.ts index 2dc5612f1..f6d3e47d5 100644 --- a/packages/quicktype-core/src/language/Objective-C.ts +++ b/packages/quicktype-core/src/language/Objective-C.ts @@ -1,34 +1,35 @@ -import { iterableSome, iterableFirst, mapContains, mapFirst, mapSome } from "collection-utils"; +import { iterableFirst, iterableSome, mapContains, mapFirst, mapSome } from "collection-utils"; +import unicode from "unicode-properties"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty } from "../Type"; -import { Type, ClassType, EnumType, ArrayType, MapType, UnionType } from "../Type"; -import { matchType, nullableFromUnion, isAnyOrNull } from "../TypeUtils"; -import { type Name } from "../Naming"; -import { Namer, funPrefixNamer } from "../Naming"; -import { type Sourcelike } from "../Source"; -import { modifySource } from "../Source"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; import { - splitIntoWords, - combineWords, - firstUpperWordStyle, - allUpperWordStyle, + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../RendererOptions"; +import { type Sourcelike, modifySource } from "../Source"; +import { + addPrefixIfNecessary, allLowerWordStyle, + allUpperWordStyle, camelCase, - utf16LegalizeCharacters, - stringEscape, - addPrefixIfNecessary, + combineWords, + fastIsUpperCase, + firstUpperWordStyle, repeatString, - fastIsUpperCase + splitIntoWords, + stringEscape, + utf16LegalizeCharacters } from "../support/Strings"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { StringOption, BooleanOption, EnumOption, getOptionValues } from "../RendererOptions"; import { assert, defined } from "../support/Support"; -import { type RenderContext } from "../Renderer"; - -import unicode from "unicode-properties"; +import { TargetLanguage } from "../TargetLanguage"; +import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, Type, UnionType } from "../Type"; +import { isAnyOrNull, matchType, nullableFromUnion } from "../TypeUtils"; export type MemoryAttribute = "assign" | "strong" | "copy"; export interface OutputFeatures { diff --git a/packages/quicktype-core/src/language/Php.ts b/packages/quicktype-core/src/language/Php.ts index 8a7eaa40b..fd0888dcf 100644 --- a/packages/quicktype-core/src/language/Php.ts +++ b/packages/quicktype-core/src/language/Php.ts @@ -1,14 +1,13 @@ +import * as _ from "lodash"; + +import { type PrimitiveStringTypeKind, type StringTypeMapping, type TransformedStringTypeKind } from ".."; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { DependencyName, funPrefixNamer } from "../Naming"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated } from "../Source"; -import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; +import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../Source"; +import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; import { allLowerWordStyle, allUpperWordStyle, @@ -27,8 +26,6 @@ import { defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; -import { type StringTypeMapping, type TransformedStringTypeKind, type PrimitiveStringTypeKind } from ".."; -import * as _ from "lodash"; export const phpOptions = { withGet: new BooleanOption("with-get", "Create Getter", true), diff --git a/packages/quicktype-core/src/language/Pike.ts b/packages/quicktype-core/src/language/Pike.ts index 637bedcac..dc57a3fc4 100644 --- a/packages/quicktype-core/src/language/Pike.ts +++ b/packages/quicktype-core/src/language/Pike.ts @@ -1,16 +1,12 @@ -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type Option } from "../RendererOptions"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type MultiWord, type Sourcelike } from "../Source"; -import { multiWord, parenIfNeeded, singleWord } from "../Source"; +import { type Option } from "../RendererOptions"; +import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../Source"; +import { isLetterOrUnderscoreOrDigit, legalizeCharacters, makeNameStyle, stringEscape } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; -import { type Type, type ClassType, type EnumType, type UnionType } from "../Type"; -import { ArrayType, MapType, PrimitiveType } from "../Type"; +import { ArrayType, type ClassType, type EnumType, MapType, PrimitiveType, type Type, type UnionType } from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { legalizeCharacters, isLetterOrUnderscoreOrDigit, stringEscape, makeNameStyle } from "../support/Strings"; export const pikeOptions = {}; diff --git a/packages/quicktype-core/src/language/Python.ts b/packages/quicktype-core/src/language/Python.ts index 5edc549b2..b6092a9d1 100644 --- a/packages/quicktype-core/src/language/Python.ts +++ b/packages/quicktype-core/src/language/Python.ts @@ -1,51 +1,54 @@ -import { TargetLanguage } from "../TargetLanguage"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type TransformedStringTypeKind, type PrimitiveStringTypeKind, type Type, type ClassProperty } from "../Type"; -import { EnumType, ClassType, UnionType } from "../Type"; +import { + arrayIntercalate, + iterableFirst, + iterableSome, + mapSortBy, + mapUpdateInto, + setUnionInto +} from "collection-utils"; +import unicode from "unicode-properties"; + +import { ConvenienceRenderer, type ForbiddenWordsInfo, topLevelNameOrder } from "../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { getOptionValues, EnumOption, BooleanOption } from "../RendererOptions"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer, topLevelNameOrder } from "../ConvenienceRenderer"; -import { type Namer, type Name } from "../Naming"; -import { funPrefixNamer, DependencyName } from "../Naming"; +import { BooleanOption, EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; +import { type MultiWord, type Sourcelike, modifySource, multiWord, parenIfNeeded, singleWord } from "../Source"; import { - splitIntoWords, + allLowerWordStyle, + allUpperWordStyle, combineWords, firstUpperWordStyle, - utf16LegalizeCharacters, - allUpperWordStyle, - allLowerWordStyle, + originalWord, + splitIntoWords, stringEscape, - originalWord + utf16LegalizeCharacters } from "../support/Strings"; -import { assertNever, panic, defined } from "../support/Support"; -import { type Sourcelike, type MultiWord } from "../Source"; -import { multiWord, singleWord, parenIfNeeded, modifySource } from "../Source"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Transformer } from "../Transformers"; +import { assertNever, defined, panic } from "../support/Support"; +import { TargetLanguage } from "../TargetLanguage"; import { - followTargetType, - transformationForType, - DecodingChoiceTransformer, ChoiceTransformer, + DecodingChoiceTransformer, DecodingTransformer, - UnionInstantiationTransformer, + EncodingTransformer, ParseStringTransformer, - UnionMemberMatchTransformer, StringifyTransformer, - EncodingTransformer + type Transformer, + UnionInstantiationTransformer, + UnionMemberMatchTransformer, + followTargetType, + transformationForType } from "../Transformers"; import { - arrayIntercalate, - setUnionInto, - mapUpdateInto, - iterableSome, - mapSortBy, - iterableFirst -} from "collection-utils"; - -import unicode from "unicode-properties"; + type ClassProperty, + ClassType, + EnumType, + type PrimitiveStringTypeKind, + type TransformedStringTypeKind, + type Type, + UnionType +} from "../Type"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; const forbiddenTypeNames = [ "Any", diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust.ts index 9c69ed654..f73a67f7b 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust.ts @@ -1,34 +1,29 @@ import { mapFirst } from "collection-utils"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { BooleanOption, EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../Source"; import { - legalizeCharacters, - splitIntoWords, - isLetterOrUnderscoreOrDigit, - combineWords, allLowerWordStyle, + combineWords, + escapeNonPrintableMapper, firstUpperWordStyle, intToHex, - utf32ConcatMap, - escapeNonPrintableMapper, - isPrintable, isAscii, - isLetterOrUnderscore + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap } from "../support/Strings"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type Type, type ClassType, type EnumType } from "../Type"; -import { UnionType } from "../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated } from "../Source"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, EnumOption, getOptionValues } from "../RendererOptions"; import { defined } from "../support/Support"; -import { type RenderContext } from "../Renderer"; +import { TargetLanguage } from "../TargetLanguage"; +import { type ClassType, type EnumType, type Type, UnionType } from "../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export enum Density { Normal = "Normal", diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts index 843c2ad4d..a736ecada 100644 --- a/packages/quicktype-core/src/language/Scala3.ts +++ b/packages/quicktype-core/src/language/Scala3.ts @@ -1,12 +1,9 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated } from "../Source"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../Source"; import { allLowerWordStyle, allUpperWordStyle, @@ -20,10 +17,17 @@ import { } from "../support/Strings"; import { assertNever } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type EnumType, type ObjectType, type Type, type UnionType } from "../Type"; -import { ArrayType, MapType } from "../Type"; +import { + ArrayType, + type ClassProperty, + type ClassType, + type EnumType, + MapType, + type ObjectType, + type Type, + type UnionType +} from "../Type"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type RenderContext } from "../Renderer"; export enum Framework { None = "None", diff --git a/packages/quicktype-core/src/language/Smithy4s.ts b/packages/quicktype-core/src/language/Smithy4s.ts index 0b28a824e..24ba6b028 100644 --- a/packages/quicktype-core/src/language/Smithy4s.ts +++ b/packages/quicktype-core/src/language/Smithy4s.ts @@ -1,12 +1,9 @@ import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated } from "../Source"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../Source"; import { allLowerWordStyle, allUpperWordStyle, @@ -20,10 +17,17 @@ import { } from "../support/Strings"; import { assertNever } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type EnumType, type ObjectType, type Type, type UnionType } from "../Type"; -import { ArrayType, MapType } from "../Type"; +import { + ArrayType, + type ClassProperty, + type ClassType, + type EnumType, + MapType, + type ObjectType, + type Type, + type UnionType +} from "../Type"; import { matchCompoundType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type RenderContext } from "../Renderer"; export enum Framework { None = "None" diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift.ts index 25cf19e02..627218116 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift.ts @@ -1,50 +1,53 @@ import { arrayIntercalate } from "collection-utils"; -import { assert, defined } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { - type Type, - type ClassType, - type UnionType, - type TypeKind, - type ClassProperty, - type TransformedStringTypeKind, - type PrimitiveStringTypeKind -} from "../Type"; -import { EnumType, ArrayType, MapType } from "../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { maybeAnnotated, modifySource } from "../Source"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type DateTimeRecognizer, DefaultDateTimeRecognizer } from "../DateTime"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type ForEachPosition, type RenderContext } from "../Renderer"; import { - legalizeCharacters, + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; +import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; +import { + addPrefixIfNecessary, + allLowerWordStyle, + allUpperWordStyle, + camelCase, + combineWords, + escapeNonPrintableMapper, + firstUpperWordStyle, + intToHex, + isDigit, isLetterOrUnderscore, isNumeric, - isDigit, - utf32ConcatMap, - escapeNonPrintableMapper, isPrintable, - intToHex, + legalizeCharacters, splitIntoWords, - combineWords, - firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle, - camelCase, - addPrefixIfNecessary + utf32ConcatMap } from "../support/Strings"; -import { type RenderContext, type ForEachPosition } from "../Renderer"; +import { assert, defined, panic } from "../support/Support"; +import { TargetLanguage } from "../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + type ClassType, + EnumType, + MapType, + type PrimitiveStringTypeKind, + type TransformedStringTypeKind, + type Type, + type TypeKind, + type UnionType +} from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; -import { panic } from "../support/Support"; -import { type DateTimeRecognizer } from "../DateTime"; -import { DefaultDateTimeRecognizer } from "../DateTime"; -import { acronymOption, acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; const MAX_SAMELINE_PROPERTIES = 4; diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts index 772260388..9db2d827a 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts @@ -1,13 +1,11 @@ import { arrayIntercalate } from "collection-utils"; -import { type ClassProperty, type ObjectType, type Type } from "../Type"; -import { ArrayType, EnumType, MapType } from "../Type"; -import { matchType } from "../TypeUtils"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; + +import { ConvenienceRenderer } from "../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, getOptionValues } from "../RendererOptions"; -import { acronymStyle, AcronymStyleOptions } from "../support/Acronyms"; +import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; +import { type Sourcelike } from "../Source"; +import { AcronymStyleOptions, acronymStyle } from "../support/Acronyms"; import { allLowerWordStyle, capitalize, @@ -18,11 +16,12 @@ import { stringEscape, utf16StringEscape } from "../support/Strings"; +import { panic } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; +import { ArrayType, type ClassProperty, EnumType, MapType, type ObjectType, type Type } from "../Type"; +import { matchType } from "../TypeUtils"; + import { legalizeName } from "./JavaScript"; -import { type Sourcelike } from "../Source"; -import { panic } from "../support/Support"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; export const typeScriptEffectSchemaOptions = { justSchema: new BooleanOption("just-schema", "Schema only", false) diff --git a/packages/quicktype-core/src/language/TypeScriptFlow.ts b/packages/quicktype-core/src/language/TypeScriptFlow.ts index e7a12f58c..f63c2d473 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow.ts @@ -1,19 +1,20 @@ -import { type Type, type ClassType } from "../Type"; -import { ArrayType, UnionType, EnumType } from "../Type"; -import { matchType, nullableFromUnion, isNamedType } from "../TypeUtils"; -import { utf16StringEscape, camelCase } from "../support/Strings"; - -import { type Sourcelike, type MultiWord } from "../Source"; -import { modifySource, singleWord, parenIfNeeded, multiWord } from "../Source"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, getOptionValues } from "../RendererOptions"; -import { type JavaScriptTypeAnnotations } from "./JavaScript"; -import { javaScriptOptions, JavaScriptTargetLanguage, JavaScriptRenderer, legalizeName } from "./JavaScript"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; +import { type MultiWord, type Sourcelike, modifySource, multiWord, parenIfNeeded, singleWord } from "../Source"; +import { camelCase, utf16StringEscape } from "../support/Strings"; import { defined, panic } from "../support/Support"; import { type TargetLanguage } from "../TargetLanguage"; -import { type RenderContext } from "../Renderer"; +import { ArrayType, type ClassType, EnumType, type Type, UnionType } from "../Type"; +import { isNamedType, matchType, nullableFromUnion } from "../TypeUtils"; + +import { + JavaScriptRenderer, + JavaScriptTargetLanguage, + type JavaScriptTypeAnnotations, + javaScriptOptions, + legalizeName +} from "./JavaScript"; import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; export const tsFlowOptions = Object.assign({}, javaScriptOptions, { diff --git a/packages/quicktype-core/src/language/TypeScriptZod.ts b/packages/quicktype-core/src/language/TypeScriptZod.ts index abc84f71e..d52c4eff7 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod.ts @@ -1,22 +1,10 @@ -import { type StringTypeMapping } from "TypeBuilder"; import { arrayIntercalate } from "collection-utils"; + import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer } from "../Naming"; -import { funPrefixNamer } from "../Naming"; +import { type Name, type Namer, funPrefixNamer } from "../Naming"; import { type RenderContext } from "../Renderer"; -import { type Option, type OptionValues } from "../RendererOptions"; -import { BooleanOption, getOptionValues } from "../RendererOptions"; +import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; import { type Sourcelike } from "../Source"; -import { TargetLanguage } from "../TargetLanguage"; -import { - type ClassProperty, - type EnumType, - type PrimitiveStringTypeKind, - type TransformedStringTypeKind, - type Type -} from "../Type"; -import { ArrayType, ClassType, ObjectType, SetOperationType } from "../Type"; -import { matchType } from "../TypeUtils"; import { AcronymStyleOptions, acronymStyle } from "../support/Acronyms"; import { allLowerWordStyle, @@ -29,6 +17,21 @@ import { utf16StringEscape } from "../support/Strings"; import { panic } from "../support/Support"; +import { TargetLanguage } from "../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + ClassType, + type EnumType, + ObjectType, + type PrimitiveStringTypeKind, + SetOperationType, + type TransformedStringTypeKind, + type Type +} from "../Type"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { matchType } from "../TypeUtils"; + import { legalizeName } from "./JavaScript"; export const typeScriptZodOptions = { diff --git a/packages/quicktype-core/src/language/ruby/index.ts b/packages/quicktype-core/src/language/ruby/index.ts index 1776a3964..10abe40d6 100644 --- a/packages/quicktype-core/src/language/ruby/index.ts +++ b/packages/quicktype-core/src/language/ruby/index.ts @@ -1,38 +1,46 @@ import unicode from "unicode-properties"; -import { type Sourcelike } from "../../Source"; -import { modifySource } from "../../Source"; -import { type Name } from "../../Naming"; -import { Namer } from "../../Naming"; -import { type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; -import { ConvenienceRenderer } from "../../ConvenienceRenderer"; -import { TargetLanguage } from "../../TargetLanguage"; -import { type Option, type OptionValues } from "../../RendererOptions"; -import { BooleanOption, EnumOption, getOptionValues, StringOption } from "../../RendererOptions"; - -import * as keywords from "./keywords"; - -const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); - -import { type Type, type EnumType, type UnionType, type ClassProperty } from "../../Type"; -import { ClassType, ArrayType, MapType } from "../../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; - +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + type Option, + type OptionValues, + StringOption, + getOptionValues +} from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; import { - legalizeCharacters, - splitIntoWords, - combineWords, - firstUpperWordStyle, - allUpperWordStyle, allLowerWordStyle, - utf32ConcatMap, - isPrintable, + allUpperWordStyle, + combineWords, escapeNonPrintableMapper, + firstUpperWordStyle, intToHex, + isLetterOrUnderscore, + isPrintable, + legalizeCharacters, snakeCase, - isLetterOrUnderscore + splitIntoWords, + utf32ConcatMap } from "../../support/Strings"; -import { type RenderContext } from "../../Renderer"; +import { TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + ClassType, + type EnumType, + MapType, + type Type, + type UnionType +} from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import * as keywords from "./keywords"; + +const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); function unicodeEscape(codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; diff --git a/packages/quicktype-core/src/rewrites/CombineClasses.ts b/packages/quicktype-core/src/rewrites/CombineClasses.ts index 4dac053fb..3fc7a29fc 100644 --- a/packages/quicktype-core/src/rewrites/CombineClasses.ts +++ b/packages/quicktype-core/src/rewrites/CombineClasses.ts @@ -1,12 +1,10 @@ -import { type Type, type ClassProperty } from "../Type"; -import { ClassType, setOperationCasesEqual } from "../Type"; -import { nonNullTypeCases, combineTypeAttributesOfTypes } from "../TypeUtils"; - import { type GraphRewriteBuilder } from "../GraphRewriting"; +import { type RunContext } from "../Run"; import { assert, panic } from "../support/Support"; +import { type ClassProperty, ClassType, type Type, setOperationCasesEqual } from "../Type"; import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { combineTypeAttributesOfTypes, nonNullTypeCases } from "../TypeUtils"; import { unifyTypes, unionBuilderForUnification } from "../UnifyClasses"; -import { type RunContext } from "../Run"; const REQUIRED_OVERLAP = 3 / 4; diff --git a/packages/quicktype-core/src/rewrites/ExpandStrings.ts b/packages/quicktype-core/src/rewrites/ExpandStrings.ts index 0482f0032..c1ee3331e 100644 --- a/packages/quicktype-core/src/rewrites/ExpandStrings.ts +++ b/packages/quicktype-core/src/rewrites/ExpandStrings.ts @@ -1,22 +1,22 @@ import { + areEqual, iterableFirst, - mapFilter, - iterableSome, iterableReduce, - setUnion, + iterableSome, + mapFilter, setIntersect, setIsSuperset, - areEqual + setUnion } from "collection-utils"; -import { type PrimitiveType } from "../Type"; -import { stringTypesForType } from "../TypeUtils"; -import { type TypeGraph, type TypeRef } from "../TypeGraph"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; -import { assert, defined } from "../support/Support"; -import { emptyTypeAttributes } from "../attributes/TypeAttributes"; import { StringTypes } from "../attributes/StringTypes"; +import { emptyTypeAttributes } from "../attributes/TypeAttributes"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; import { type RunContext } from "../Run"; +import { assert, defined } from "../support/Support"; +import { type PrimitiveType } from "../Type"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { stringTypesForType } from "../TypeUtils"; const MIN_LENGTH_FOR_ENUM = 10; diff --git a/packages/quicktype-core/src/rewrites/FlattenStrings.ts b/packages/quicktype-core/src/rewrites/FlattenStrings.ts index fa43717e5..6982a94da 100644 --- a/packages/quicktype-core/src/rewrites/FlattenStrings.ts +++ b/packages/quicktype-core/src/rewrites/FlattenStrings.ts @@ -1,12 +1,12 @@ import { iterableFirst } from "collection-utils"; -import { type PrimitiveType, type UnionType, type Type } from "../Type"; -import { stringTypesForType, combineTypeAttributesOfTypes } from "../TypeUtils"; -import { type TypeGraph, type TypeRef } from "../TypeGraph"; -import { type StringTypeMapping } from "../TypeBuilder"; +import { combineTypeAttributes } from "../attributes/TypeAttributes"; import { type GraphRewriteBuilder } from "../GraphRewriting"; import { assert, defined } from "../support/Support"; -import { combineTypeAttributes } from "../attributes/TypeAttributes"; +import { type PrimitiveType, type Type, type UnionType } from "../Type"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { combineTypeAttributesOfTypes, stringTypesForType } from "../TypeUtils"; // A union needs replacing if it contains more than one string type, one of them being // a basic string type. diff --git a/packages/quicktype-core/src/rewrites/FlattenUnions.ts b/packages/quicktype-core/src/rewrites/FlattenUnions.ts index a834002e8..cca90fca4 100644 --- a/packages/quicktype-core/src/rewrites/FlattenUnions.ts +++ b/packages/quicktype-core/src/rewrites/FlattenUnions.ts @@ -1,16 +1,14 @@ -import { setFilter, iterableSome } from "collection-utils"; +import { iterableSome, setFilter } from "collection-utils"; -import { type TypeGraph, type TypeRef } from "../TypeGraph"; -import { derefTypeRef } from "../TypeGraph"; -import { type Type } from "../Type"; -import { UnionType, IntersectionType } from "../Type"; -import { makeGroupsToFlatten } from "../TypeUtils"; -import { assert } from "../support/Support"; -import { type StringTypeMapping } from "../TypeBuilder"; +import { emptyTypeAttributes } from "../attributes/TypeAttributes"; import { type GraphRewriteBuilder } from "../GraphRewriting"; -import { unifyTypes, UnifyUnionBuilder } from "../UnifyClasses"; import { messageAssert } from "../Messages"; -import { emptyTypeAttributes } from "../attributes/TypeAttributes"; +import { assert } from "../support/Support"; +import { IntersectionType, type Type, UnionType } from "../Type"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type TypeGraph, type TypeRef, derefTypeRef } from "../TypeGraph"; +import { makeGroupsToFlatten } from "../TypeUtils"; +import { UnifyUnionBuilder, unifyTypes } from "../UnifyClasses"; export function flattenUnions( graph: TypeGraph, diff --git a/packages/quicktype-core/src/rewrites/InferMaps.ts b/packages/quicktype-core/src/rewrites/InferMaps.ts index 43e30182c..e63803745 100644 --- a/packages/quicktype-core/src/rewrites/InferMaps.ts +++ b/packages/quicktype-core/src/rewrites/InferMaps.ts @@ -1,15 +1,13 @@ -import { iterableFirst, iterableEvery, setMap } from "collection-utils"; +import { iterableEvery, iterableFirst, setMap } from "collection-utils"; -import { type Type, type ClassProperty } from "../Type"; -import { ClassType, setOperationCasesEqual, isPrimitiveStringTypeKind } from "../Type"; -import { removeNullFromType } from "../TypeUtils"; +import { type GraphRewriteBuilder } from "../GraphRewriting"; +import { type MarkovChain, evaluate, load } from "../MarkovChain"; import { defined, panic } from "../support/Support"; -import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { type ClassProperty, ClassType, type Type, isPrimitiveStringTypeKind, setOperationCasesEqual } from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { removeNullFromType } from "../TypeUtils"; import { unifyTypes, unionBuilderForUnification } from "../UnifyClasses"; -import { type MarkovChain } from "../MarkovChain"; -import { load, evaluate } from "../MarkovChain"; const mapSizeThreshold = 20; const stringMapSizeThreshold = 50; diff --git a/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts b/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts index 99acbc145..2e8504d62 100644 --- a/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts +++ b/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts @@ -1,11 +1,11 @@ -import { setFilter, iterableFirst, mapMap, setMap } from "collection-utils"; +import { iterableFirst, mapMap, setFilter, setMap } from "collection-utils"; -import { type TypeGraph, type TypeRef } from "../TypeGraph"; -import { type StringTypeMapping } from "../TypeBuilder"; +import { emptyTypeAttributes } from "../attributes/TypeAttributes"; import { type GraphRewriteBuilder } from "../GraphRewriting"; -import { type ObjectType, type ClassProperty } from "../Type"; import { defined } from "../support/Support"; -import { emptyTypeAttributes } from "../attributes/TypeAttributes"; +import { type ClassProperty, type ObjectType } from "../Type"; +import { type StringTypeMapping } from "../TypeBuilder"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; export function replaceObjectType( graph: TypeGraph, diff --git a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts index a3a3016be..ffe2f8a64 100644 --- a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts +++ b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts @@ -1,36 +1,41 @@ import { - iterableFirst, iterableEvery, - setFilter, + iterableFind, + iterableFirst, + mapMap, mapMapEntries, mapMergeWithInto, - mapMap, mapUpdateInto, - setMap, - iterableFind, + setFilter, setIntersect, + setMap, setUnionInto } from "collection-utils"; -import { type TypeGraph, type TypeRef } from "../TypeGraph"; -import { type StringTypeMapping, type TypeBuilder } from "../TypeBuilder"; +import { + type TypeAttributes, + combineTypeAttributes, + emptyTypeAttributes, + makeTypeAttributesInferred +} from "../attributes/TypeAttributes"; import { type GraphRewriteBuilder, type TypeLookerUp } from "../GraphRewriting"; -import { type UnionTypeProvider, type TypeAttributeMap } from "../UnionBuilder"; -import { UnionBuilder } from "../UnionBuilder"; -import { type Type, type PrimitiveTypeKind, type TypeKind } from "../Type"; +import { assert, defined, mustNotHappen, panic } from "../support/Support"; import { + ArrayType, + GenericClassProperty, IntersectionType, + ObjectType, + type PrimitiveTypeKind, + type Type, + type TypeKind, UnionType, - ArrayType, - isPrimitiveTypeKind, isNumberTypeKind, - GenericClassProperty, - ObjectType + isPrimitiveTypeKind } from "../Type"; -import { setOperationMembersRecursively, matchTypeExhaustive, makeGroupsToFlatten } from "../TypeUtils"; -import { assert, defined, panic, mustNotHappen } from "../support/Support"; -import { type TypeAttributes } from "../attributes/TypeAttributes"; -import { combineTypeAttributes, emptyTypeAttributes, makeTypeAttributesInferred } from "../attributes/TypeAttributes"; +import { type StringTypeMapping, type TypeBuilder } from "../TypeBuilder"; +import { type TypeGraph, type TypeRef } from "../TypeGraph"; +import { makeGroupsToFlatten, matchTypeExhaustive, setOperationMembersRecursively } from "../TypeUtils"; +import { type TypeAttributeMap, UnionBuilder, type UnionTypeProvider } from "../UnionBuilder"; function canResolve(t: IntersectionType): boolean { const members = setOperationMembersRecursively(t, undefined)[0]; diff --git a/packages/quicktype-core/src/support/Acronyms.ts b/packages/quicktype-core/src/support/Acronyms.ts index 24a40dec1..8c3eabcf1 100644 --- a/packages/quicktype-core/src/support/Acronyms.ts +++ b/packages/quicktype-core/src/support/Acronyms.ts @@ -1,5 +1,7 @@ import { EnumOption } from "../RendererOptions"; -import { allUpperWordStyle, firstUpperWordStyle, originalWord, allLowerWordStyle } from "./Strings"; + +// eslint-disable-next-line import/no-cycle +import { allLowerWordStyle, allUpperWordStyle, firstUpperWordStyle, originalWord } from "./Strings"; export const acronyms: string[] = [ "aaa", @@ -1096,7 +1098,7 @@ export const acronyms: string[] = [ "zma", "zoi", "zope", - "zpl", + "zpl" ]; export enum AcronymStyleOptions { @@ -1114,19 +1116,19 @@ export const acronymOption = function (defaultOption: AcronymStyleOptions) { [AcronymStyleOptions.Original, AcronymStyleOptions.Original], [AcronymStyleOptions.Pascal, AcronymStyleOptions.Pascal], [AcronymStyleOptions.Camel, AcronymStyleOptions.Camel], - [AcronymStyleOptions.Lower, AcronymStyleOptions.Lower], + [AcronymStyleOptions.Lower, AcronymStyleOptions.Lower] ], defaultOption, - "secondary", + "secondary" ); }; -export function acronymStyle (style: AcronymStyleOptions): (s: string) => string { - const options: { [key: string]: (s: string) => string, } = { +export function acronymStyle(style: AcronymStyleOptions): (s: string) => string { + const options: { [key: string]: (s: string) => string } = { [AcronymStyleOptions.Pascal]: allUpperWordStyle, [AcronymStyleOptions.Camel]: firstUpperWordStyle, [AcronymStyleOptions.Original]: originalWord, - [AcronymStyleOptions.Lower]: allLowerWordStyle, + [AcronymStyleOptions.Lower]: allLowerWordStyle }; return options[style]; diff --git a/packages/quicktype-core/src/support/Strings.ts b/packages/quicktype-core/src/support/Strings.ts index 555b861f3..1ea40e3d6 100644 --- a/packages/quicktype-core/src/support/Strings.ts +++ b/packages/quicktype-core/src/support/Strings.ts @@ -1,7 +1,11 @@ -import { assert, defined, panic, assertNever } from "./Support"; -import { acronyms } from "./Acronyms"; +import unicode from "unicode-properties"; + import { messageAssert } from "../Messages"; +// eslint-disable-next-line import/no-cycle +import { acronyms } from "./Acronyms"; +import { assert, assertNever, defined, panic } from "./Support"; + export type NamingStyle = | "pascal" | "camel" @@ -10,8 +14,6 @@ export type NamingStyle = | "pascal-upper-acronyms" | "camel-upper-acronyms"; -import unicode from "unicode-properties"; - function computeAsciiMap(mapper: (codePoint: number) => string): { charNoEscapeMap: number[]; charStringMap: string[]; diff --git a/packages/quicktype-core/src/support/Support.ts b/packages/quicktype-core/src/support/Support.ts index 0fef6624a..31e78fd4b 100644 --- a/packages/quicktype-core/src/support/Support.ts +++ b/packages/quicktype-core/src/support/Support.ts @@ -1,8 +1,9 @@ import { Base64 } from "js-base64"; import * as pako from "pako"; -import { messageError } from "../Messages"; import * as YAML from "yaml"; +import { messageError } from "../Messages"; + export interface StringMap { [name: string]: any; } diff --git a/packages/quicktype-graphql-input/src/index.ts b/packages/quicktype-graphql-input/src/index.ts index c2cc29cbb..a6c1f53e2 100644 --- a/packages/quicktype-graphql-input/src/index.ts +++ b/packages/quicktype-graphql-input/src/index.ts @@ -1,39 +1,35 @@ +import { iterableFirst, mapFromObject, setMap } from "collection-utils"; +import * as graphql from "graphql/language"; import { + type DirectiveNode, type DocumentNode, - type SelectionSetNode, - type SelectionNode, - type OperationDefinitionNode, + type FieldNode, type FragmentDefinitionNode, - type DirectiveNode, - type FieldNode + type OperationDefinitionNode, + type SelectionNode, + type SelectionSetNode } from "graphql/language/ast"; -import * as graphql from "graphql/language"; -import { setMap, iterableFirst, mapFromObject } from "collection-utils"; - import { type ClassProperty, + type Input, + type RunContext, + StringTypes, + type TypeAttributes, type TypeBuilder, + TypeNames, type TypeRef, - type TypeAttributes, - type Input, - type RunContext -} from "quicktype-core"; -import { UnionType, - removeNullFromUnion, assertNever, - panic, - TypeNames, + derefTypeRef, + emptyTypeAttributes, makeNamesTypeAttributes, - namesTypeAttributeKind, messageAssert, - emptyTypeAttributes, - StringTypes, - derefTypeRef + namesTypeAttributeKind, + panic, + removeNullFromUnion } from "quicktype-core"; -import { type GraphQLSchema } from "./GraphQLSchema"; -import { TypeKind } from "./GraphQLSchema"; +import { type GraphQLSchema, TypeKind } from "./GraphQLSchema"; interface GQLType { description?: string; diff --git a/packages/quicktype-typescript-input/src/index.ts b/packages/quicktype-typescript-input/src/index.ts index 47696ce83..dc31c6e9d 100644 --- a/packages/quicktype-typescript-input/src/index.ts +++ b/packages/quicktype-typescript-input/src/index.ts @@ -1,15 +1,12 @@ +import { type PartialArgs, generateSchema } from "@mark.probst/typescript-json-schema"; +import { type JSONSchemaSourceData, defined, messageError } from "quicktype-core"; import * as ts from "typescript"; -import { type PartialArgs} from "@mark.probst/typescript-json-schema"; -import { generateSchema } from "@mark.probst/typescript-json-schema"; - -import { type JSONSchemaSourceData} from "quicktype-core"; -import { defined, messageError } from "quicktype-core"; const settings: PartialArgs = { required: true, titles: true, topRef: true, - noExtraProps: true, + noExtraProps: true }; const compilerOptions: ts.CompilerOptions = { @@ -20,18 +17,18 @@ const compilerOptions: ts.CompilerOptions = { module: ts.ModuleKind.CommonJS, strictNullChecks: true, typeRoots: [], - rootDir: ".", + rootDir: "." }; // FIXME: We're stringifying and then parsing this schema again. Just pass around // the schema directly. -export function schemaForTypeScriptSources (sourceFileNames: string[]): JSONSchemaSourceData { +export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchemaSourceData { const program = ts.createProgram(sourceFileNames, compilerOptions); const diagnostics = ts.getPreEmitDiagnostics(program); const error = diagnostics.find(d => d.category === ts.DiagnosticCategory.Error); if (error !== undefined) { return messageError("TypeScriptCompilerError", { - message: ts.flattenDiagnosticMessageText(error.messageText, "\n"), + message: ts.flattenDiagnosticMessageText(error.messageText, "\n") }); } diff --git a/src/CompressedJSONFromStream.ts b/src/CompressedJSONFromStream.ts index c442b2f8f..40db6d87b 100644 --- a/src/CompressedJSONFromStream.ts +++ b/src/CompressedJSONFromStream.ts @@ -1,8 +1,8 @@ import { type Readable } from "readable-stream"; -import { type Value } from "quicktype-core"; -import { CompressedJSON } from "quicktype-core"; import { Parser } from "stream-json"; +import { CompressedJSON, type Value } from "quicktype-core"; + const methodMap: { [name: string]: string } = { startObject: "pushObjectContext", endObject: "finishObject", diff --git a/src/GraphQLIntrospection.ts b/src/GraphQLIntrospection.ts index b62122ec5..840cf3c5a 100644 --- a/src/GraphQLIntrospection.ts +++ b/src/GraphQLIntrospection.ts @@ -1,19 +1,19 @@ -import { panic } from "quicktype-core"; -import { introspectionQuery } from "graphql"; import { exceptionToString } from "@glideapps/ts-necessities"; - import fetch from "cross-fetch"; +import { introspectionQuery } from "graphql"; + +import { panic } from "quicktype-core"; // https://github.com/apollographql/apollo-codegen/blob/master/src/downloadSchema.ts -const defaultHeaders: { [name: string]: string, } = { +const defaultHeaders: { [name: string]: string } = { Accept: "application/json", - "Content-Type": "application/json", + "Content-Type": "application/json" }; const headerRegExp = /^([^:]+):\s*(.*)$/; -export async function introspectServer (url: string, method: string, headerStrings: string[]): Promise { - const headers: { [name: string]: string, } = {}; +export async function introspectServer(url: string, method: string, headerStrings: string[]): Promise { + const headers: { [name: string]: string } = {}; for (const name of Object.getOwnPropertyNames(defaultHeaders)) { headers[name] = defaultHeaders[name]; @@ -33,7 +33,7 @@ export async function introspectServer (url: string, method: string, headerStrin const response = await fetch(url, { method, headers: headers, - body: JSON.stringify({ query: introspectionQuery }), + body: JSON.stringify({ query: introspectionQuery }) }); result = await response.json(); diff --git a/src/TypeSource.ts b/src/TypeSource.ts index ab0580889..1c58e2e73 100644 --- a/src/TypeSource.ts +++ b/src/TypeSource.ts @@ -1,6 +1,6 @@ import { type Readable } from "readable-stream"; -import { type JSONSourceData, type JSONSchemaSourceData } from "quicktype-core"; +import { type JSONSchemaSourceData, type JSONSourceData } from "quicktype-core"; import { type GraphQLSourceData } from "quicktype-graphql-input"; export interface JSONTypeSource extends JSONSourceData { diff --git a/src/URLGrammar.ts b/src/URLGrammar.ts index 25ac55c5c..3ffdc26a8 100644 --- a/src/URLGrammar.ts +++ b/src/URLGrammar.ts @@ -1,6 +1,6 @@ -import { panic, checkStringMap, checkArray } from "quicktype-core"; +import { checkArray, checkStringMap, panic } from "quicktype-core"; -function expand (json: any): string[] { +function expand(json: any): string[] { if (typeof json === "string") { return [json]; } @@ -37,9 +37,9 @@ function expand (json: any): string[] { return panic(`Value is not a valid URL grammar: ${json}`); } -export function urlsFromURLGrammar (json: any): { [name: string]: string[], } { +export function urlsFromURLGrammar(json: any): { [name: string]: string[] } { const topLevelMap = checkStringMap(json); - const results: { [name: string]: string[], } = {}; + const results: { [name: string]: string[] } = {}; for (const name of Object.getOwnPropertyNames(topLevelMap)) { results[name] = expand(topLevelMap[name]); diff --git a/src/index.ts b/src/index.ts index a71cfe3f5..6804ef731 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,65 +1,63 @@ #!/usr/bin/env node import * as fs from "fs"; import * as path from "path"; + +import { exceptionToString } from "@glideapps/ts-necessities"; +import chalk from "chalk"; +// eslint-disable-next-line @typescript-eslint/no-redeclare +import { definedMap, hasOwnProperty, mapFromObject, mapMap, withDefault } from "collection-utils"; +import commandLineArgs from "command-line-args"; +import getUsage from "command-line-usage"; import * as _ from "lodash"; import { type Readable } from "readable-stream"; -import { hasOwnProperty, definedMap, withDefault, mapFromObject, mapMap } from "collection-utils"; -import { exceptionToString } from "@glideapps/ts-necessities"; +import stringToStream from "string-to-stream"; +import _wordwrap from "wordwrap"; import { + FetchingJSONSchemaStore, + InputData, + IssueAnnotationData, + JSONInput, + JSONSchemaInput, + type JSONSourceData, + type OptionDefinition, type Options, type RendererOptions, type SerializedRenderResult, type TargetLanguage, - type OptionDefinition, - type JSONSourceData -} from "quicktype-core"; -import { + assert, + assertNever, + capitalize, + defaultTargetLanguages, + defined, + getStream, getTargetLanguage, - quicktypeMultiFile, + inferenceFlagNames, + inferenceFlags, languageNamed, - InputData, - JSONSchemaInput, - defaultTargetLanguages, - IssueAnnotationData, + messageAssert, + messageError, panic, - assert, - defined, - assertNever, parseJSON, - trainMarkovChain, - messageError, - messageAssert, + quicktypeMultiFile, + readFromFileOrURL, + readableFromFileOrURL, sourcesFromPostmanCollection, - inferenceFlags, - inferenceFlagNames, splitIntoWords, - capitalize, - JSONInput, - getStream, - readableFromFileOrURL, - readFromFileOrURL, - FetchingJSONSchemaStore + trainMarkovChain } from "quicktype-core"; -import { schemaForTypeScriptSources } from "quicktype-typescript-input"; import { GraphQLInput } from "quicktype-graphql-input"; +import { schemaForTypeScriptSources } from "quicktype-typescript-input"; -import { urlsFromURLGrammar } from "./URLGrammar"; -import { introspectServer } from "./GraphQLIntrospection"; -import { type JSONTypeSource, type TypeSource, type GraphQLTypeSource, type SchemaTypeSource } from "./TypeSource"; -import { CompressedJSONFromStream } from "./CompressedJSONFromStream"; - -import stringToStream from "string-to-stream"; +import packageJSON from "../package.json"; -import commandLineArgs from "command-line-args"; -import getUsage from "command-line-usage"; -import chalk from "chalk"; +import { CompressedJSONFromStream } from "./CompressedJSONFromStream"; +import { introspectServer } from "./GraphQLIntrospection"; +import { type GraphQLTypeSource, type JSONTypeSource, type SchemaTypeSource, type TypeSource } from "./TypeSource"; +import { urlsFromURLGrammar } from "./URLGrammar"; -import _wordwrap from "wordwrap"; const wordWrap: (s: string) => string = _wordwrap(90); -import packageJSON from "../package.json"; - export interface CLIOptions { // We use this to access the inference flags [option: string]: any; From a47609a2c2665076a70cf9f99b7e800072e9b71f Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 09:28:49 -0700 Subject: [PATCH 22/80] reduce excess style rules --- .eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index c14276ec1..a5cf75933 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -69,10 +69,11 @@ "@typescript-eslint/consistent-type-definitions": ["error", "interface"], "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }], "@typescript-eslint/explicit-function-return-type": "warn", - "@typescript-eslint/indent": ["error", 4], + "@typescript-eslint/indent": "off", "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true }], "@typescript-eslint/member-delimiter-style": "off", "@typescript-eslint/naming-convention": "error", + "@typescript-eslint/no-base-to-string": "warn", "@typescript-eslint/no-empty-interface": "warn", "@typescript-eslint/no-extra-parens": "off", "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], From b53613620264b5b9d4bdc9547ded2dad0e4f8707 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 19:26:56 -0700 Subject: [PATCH 23/80] fix any types fixup! fix any types fixup! fix any types --- .../quicktype-core/src/ConvenienceRenderer.ts | 6 +- packages/quicktype-core/src/GraphRewriting.ts | 2 +- packages/quicktype-core/src/Messages.ts | 13 ++-- .../quicktype-core/src/RendererOptions.ts | 15 ++--- packages/quicktype-core/src/Run.ts | 5 +- packages/quicktype-core/src/TargetLanguage.ts | 13 ++-- packages/quicktype-core/src/Transformers.ts | 37 ++++++----- packages/quicktype-core/src/Type.ts | 9 +-- packages/quicktype-core/src/TypeGraph.ts | 6 +- packages/quicktype-core/src/TypeUtils.ts | 2 +- .../src/attributes/AccessorNames.ts | 6 +- .../src/attributes/Description.ts | 4 +- .../src/attributes/StringTypes.ts | 2 +- .../src/attributes/TypeAttributes.ts | 6 +- .../src/input/CompressedJSON.ts | 4 +- packages/quicktype-core/src/input/Inputs.ts | 1 + .../src/input/JSONSchemaInput.ts | 61 +++++++++---------- .../src/input/PostmanCollection.ts | 11 ++-- .../src/input/io/get-stream/buffer-stream.ts | 1 + .../src/input/io/get-stream/index.ts | 1 + packages/quicktype-core/src/language/CJSON.ts | 7 ++- .../quicktype-core/src/language/CPlusPlus.ts | 34 +++++------ .../quicktype-core/src/language/CSharp.ts | 8 +-- .../quicktype-core/src/language/Crystal.ts | 3 +- packages/quicktype-core/src/language/Dart.ts | 5 +- packages/quicktype-core/src/language/Elm.ts | 5 +- .../quicktype-core/src/language/Golang.ts | 5 +- .../quicktype-core/src/language/Haskell.ts | 8 +-- .../quicktype-core/src/language/JSONSchema.ts | 11 ++-- packages/quicktype-core/src/language/Java.ts | 5 +- .../quicktype-core/src/language/JavaScript.ts | 8 +-- .../src/language/JavaScriptPropTypes.ts | 9 +-- .../quicktype-core/src/language/Kotlin.ts | 8 +-- .../src/language/Objective-C.ts | 8 +-- packages/quicktype-core/src/language/Php.ts | 5 +- packages/quicktype-core/src/language/Pike.ts | 3 +- .../quicktype-core/src/language/Python.ts | 5 +- packages/quicktype-core/src/language/Rust.ts | 7 ++- .../quicktype-core/src/language/Scala3.ts | 8 +-- .../quicktype-core/src/language/Smithy4s.ts | 8 +-- packages/quicktype-core/src/language/Swift.ts | 5 +- .../src/language/TypeScriptEffectSchema.ts | 5 +- .../src/language/TypeScriptFlow.ts | 12 ++-- .../src/language/TypeScriptZod.ts | 8 +-- .../quicktype-core/src/language/ruby/index.ts | 5 +- .../quicktype-core/src/support/Support.ts | 43 +++++++------ packages/quicktype-core/src/types.ts | 6 ++ packages/quicktype-graphql-input/src/index.ts | 6 +- src/CompressedJSONFromStream.ts | 5 +- src/URLGrammar.ts | 6 +- src/index.ts | 7 ++- 51 files changed, 250 insertions(+), 223 deletions(-) create mode 100644 packages/quicktype-core/src/types.ts diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index 8de7ac678..df5e02578 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -775,7 +775,7 @@ export abstract class ConvenienceRenderer extends Renderer { protected forEachSpecificNamedType( blankLocations: BlankLineConfig, - types: Iterable<[any, T]>, + types: Iterable<[T, T]>, f: (t: T, name: Name, position: ForEachPosition) => void ): void { this.forEachWithBlankLines(types, blankLocations, (t, _, pos) => f(t, this.nameForNamedType(t), pos)); @@ -788,7 +788,7 @@ export abstract class ConvenienceRenderer extends Renderer { | ((o: ObjectType, objectName: Name, position: ForEachPosition) => void) ): void { // FIXME: This is ugly. - this.forEachSpecificNamedType(blankLocations, defined(this._namedObjects).entries(), f as any); + this.forEachSpecificNamedType(blankLocations, defined(this._namedObjects).entries(), f); } protected forEachEnum( @@ -834,7 +834,7 @@ export abstract class ConvenienceRenderer extends Renderer { if (t instanceof ObjectType) { // FIXME: This is ugly. We can't runtime check that the function // takes full object types if we have them. - (objectFunc as any)(t, name, pos); + objectFunc(t, name, pos); } else if (t instanceof EnumType) { enumFunc(t, name, pos); } else if (t instanceof UnionType) { diff --git a/packages/quicktype-core/src/GraphRewriting.ts b/packages/quicktype-core/src/GraphRewriting.ts index 546877575..d3c78d811 100644 --- a/packages/quicktype-core/src/GraphRewriting.ts +++ b/packages/quicktype-core/src/GraphRewriting.ts @@ -222,7 +222,7 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ private _printIndent = 0; public constructor( - protected readonly originalGraph: TypeGraph, + public readonly originalGraph: TypeGraph, stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, graphHasProvenanceAttributes: boolean, diff --git a/packages/quicktype-core/src/Messages.ts b/packages/quicktype-core/src/Messages.ts index 6f35dae1c..0c945480a 100644 --- a/packages/quicktype-core/src/Messages.ts +++ b/packages/quicktype-core/src/Messages.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { type Ref } from "./input/JSONSchemaInput"; import { type StringMap } from "./support/Support"; @@ -6,9 +7,9 @@ export type ErrorProperties = // Misc | { - kind: "MiscJSONParseError"; - properties: { address: string; description: string; message: string }; - } + kind: "MiscJSONParseError"; + properties: { address: string; description: string; message: string }; + } | { kind: "MiscReadError"; properties: { fileOrURL: string; message: string } } | { kind: "MiscUnicodeHighSurrogateWithoutLowSurrogate"; properties: {} } | { kind: "MiscInvalidMinMaxConstraint"; properties: { max: number; min: number } } @@ -36,9 +37,9 @@ export type ErrorProperties = | { kind: "SchemaIDMustHaveAddress"; properties: { id: string; ref: Ref } } | { kind: "SchemaWrongAccessorEntryArrayLength"; properties: { operation: string; ref: Ref } } | { - kind: "SchemaSetOperationCasesIsNotArray"; - properties: { cases: any; operation: string; ref: Ref }; - } + kind: "SchemaSetOperationCasesIsNotArray"; + properties: { cases: any; operation: string; ref: Ref }; + } | { kind: "SchemaMoreThanOneUnionMemberName"; properties: { names: string[] } } | { kind: "SchemaCannotGetTypesFromBoolean"; properties: { ref: string } } | { kind: "SchemaCannotIndexArrayWithNonNumber"; properties: { actual: string; ref: Ref } } diff --git a/packages/quicktype-core/src/RendererOptions.ts b/packages/quicktype-core/src/RendererOptions.ts index 9e4b17542..77f95c228 100644 --- a/packages/quicktype-core/src/RendererOptions.ts +++ b/packages/quicktype-core/src/RendererOptions.ts @@ -3,6 +3,7 @@ import { hasOwnProperty } from "collection-utils"; import { messageError } from "./Messages"; import { assert } from "./support/Support"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "./types"; /** * Primary options show up in the web UI in the "Language" settings tab, @@ -13,7 +14,7 @@ export type OptionKind = "primary" | "secondary"; export interface OptionDefinition { alias?: string; defaultOption?: boolean; - defaultValue?: any; + defaultValue?: FixMeOptionsAnyType; description: string; kind?: OptionKind; legalValues?: string[]; @@ -37,7 +38,7 @@ export abstract class Option { assert(definition.kind !== undefined, "Renderer option kind must be defined"); } - public getValue(values: { [name: string]: any }): T { + public getValue(values: FixMeOptionsType): T { const value = values[this.definition.name]; if (value === undefined) { return this.definition.defaultValue; @@ -54,11 +55,11 @@ export abstract class Option { export type OptionValueType = O extends Option ? T : never; export type OptionValues = { [P in keyof T]: OptionValueType }; -export function getOptionValues }>( +export function getOptionValues }>( options: T, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: FixMeOptionsType ): OptionValues { - const optionValues: { [name: string]: any } = {}; + const optionValues: FixMeOptionsType = {}; for (const name of Object.getOwnPropertyNames(options)) { optionValues[name] = options[name].getValue(untypedOptionValues); } @@ -101,7 +102,7 @@ export class BooleanOption extends Option { }; } - public getValue(values: { [name: string]: any }): boolean { + public getValue(values: FixMeOptionsType): boolean { let value = values[this.definition.name]; if (value === undefined) { value = this.definition.defaultValue; @@ -177,7 +178,7 @@ export class EnumOption extends Option { } } - public getValue(values: { [name: string]: any }): T { + public getValue(values: FixMeOptionsType): T { let name: string = values[this.definition.name]; if (name === undefined) { name = this.definition.defaultValue; diff --git a/packages/quicktype-core/src/Run.ts b/packages/quicktype-core/src/Run.ts index 42a5e5b31..dac66c17e 100644 --- a/packages/quicktype-core/src/Run.ts +++ b/packages/quicktype-core/src/Run.ts @@ -20,6 +20,7 @@ import { type MultiFileRenderResult, type TargetLanguage } from "./TargetLanguag import { type TransformedStringTypeKind } from "./Type"; import { type StringTypeMapping, TypeBuilder } from "./TypeBuilder"; import { type TypeGraph, noneToAny, optionalToNullable, removeIndirectionIntersections } from "./TypeGraph"; +import { type FixMeOptionsType } from "./types"; export function getTargetLanguage(nameOrInstance: string | TargetLanguage): TargetLanguage { if (typeof nameOrInstance === "object") { @@ -231,9 +232,9 @@ class Run implements RunContext { // we sometimes get. this._options = Object.assign({}, defaultOptions, defaultInferenceFlags); for (const k of Object.getOwnPropertyNames(options)) { - const v = (options as any)[k]; + const v = (options as FixMeOptionsType)[k]; if (v !== undefined) { - (this._options as any)[k] = v; + (this._options as FixMeOptionsType)[k] = v; } } } diff --git a/packages/quicktype-core/src/TargetLanguage.ts b/packages/quicktype-core/src/TargetLanguage.ts index 07fe51409..19f6bfea7 100644 --- a/packages/quicktype-core/src/TargetLanguage.ts +++ b/packages/quicktype-core/src/TargetLanguage.ts @@ -1,6 +1,6 @@ import { mapMap } from "collection-utils"; -import { type ConvenienceRenderer } from "./ConvenienceRenderer"; +import { ConvenienceRenderer } from "./ConvenienceRenderer"; import { type DateTimeRecognizer, DefaultDateTimeRecognizer } from "./DateTime"; import { type RenderContext, type Renderer } from "./Renderer"; import { type Option, type OptionDefinition } from "./RendererOptions"; @@ -10,6 +10,7 @@ import { defined } from "./support/Support"; import { type Type } from "./Type"; import { type StringTypeMapping } from "./TypeBuilder"; import { type TypeGraph } from "./TypeGraph"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "./types"; export type MultiFileRenderResult = ReadonlyMap; @@ -20,7 +21,7 @@ export abstract class TargetLanguage { public readonly extension: string ) {} - protected abstract getOptions(): Array>; + protected abstract getOptions(): Array>; public get optionDefinitions(): OptionDefinition[] { return this.getOptions().map(o => o.definition); @@ -41,14 +42,14 @@ export abstract class TargetLanguage { return defined(this.names[0]); } - protected abstract makeRenderer(renderContext: RenderContext, optionValues: { [name: string]: any }): Renderer; + protected abstract makeRenderer(renderContext: RenderContext, optionValues: FixMeOptionsType): Renderer; public renderGraphAndSerialize( typeGraph: TypeGraph, givenOutputFilename: string, alphabetizeProperties: boolean, leadingComments: Comment[] | undefined, - rendererOptions: { [name: string]: any }, + rendererOptions: FixMeOptionsType, indentation?: string ): MultiFileRenderResult { if (indentation === undefined) { @@ -57,8 +58,8 @@ export abstract class TargetLanguage { const renderContext = { typeGraph, leadingComments }; const renderer = this.makeRenderer(renderContext, rendererOptions); - if ((renderer as any).setAlphabetizeProperties !== undefined) { - (renderer as ConvenienceRenderer).setAlphabetizeProperties(alphabetizeProperties); + if (renderer instanceof ConvenienceRenderer) { + renderer.setAlphabetizeProperties(alphabetizeProperties); } const renderResult = renderer.render(givenOutputFilename); diff --git a/packages/quicktype-core/src/Transformers.ts b/packages/quicktype-core/src/Transformers.ts index 01de933a8..b1b93bfa3 100644 --- a/packages/quicktype-core/src/Transformers.ts +++ b/packages/quicktype-core/src/Transformers.ts @@ -54,8 +54,7 @@ export abstract class Transformer { public abstract reconstitute(builder: TBuilder): Transformer; - public equals(other: any): boolean { - if (!(other instanceof Transformer)) return false; + public equals(other: T): boolean { return this.sourceTypeRef === other.sourceTypeRef; } @@ -97,7 +96,7 @@ export abstract class ProducerTransformer extends Transformer { return super.getNumberOfNodes() + getNumberOfNodes(this.consumer); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof ProducerTransformer)) return false; return areEqual(this.consumer, other.consumer); @@ -132,7 +131,7 @@ export abstract class MatchTransformer extends Transformer { return super.getNumberOfNodes() + this.transformer.getNumberOfNodes(); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof MatchTransformer)) return false; return this.transformer.equals(other.transformer); @@ -180,7 +179,7 @@ export class DecodingTransformer extends ProducerTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; return other instanceof DecodingTransformer; } @@ -203,7 +202,7 @@ export class EncodingTransformer extends Transformer { return new EncodingTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof EncodingTransformer)) return false; return true; @@ -283,7 +282,7 @@ export class ArrayDecodingTransformer extends ProducerTransformer { return h; } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof ArrayDecodingTransformer)) return false; if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) return false; @@ -343,7 +342,7 @@ export class ArrayEncodingTransformer extends Transformer { return addHashCode(h, this.itemTransformer.hashCode()); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof ArrayEncodingTransformer)) return false; if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) return false; @@ -415,7 +414,7 @@ export class ChoiceTransformer extends Transformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof ChoiceTransformer)) return false; return areEqual(this.transformers, other.transformers); @@ -597,7 +596,7 @@ export class DecodingChoiceTransformer extends Transformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof DecodingChoiceTransformer)) return false; if (!areEqual(this.nullTransformer, other.nullTransformer)) return false; @@ -673,7 +672,7 @@ export class UnionMemberMatchTransformer extends MatchTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof UnionMemberMatchTransformer)) return false; return this.memberTypeRef === other.memberTypeRef; @@ -736,7 +735,7 @@ export class StringMatchTransformer extends MatchTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof StringMatchTransformer)) return false; return this.stringCase !== other.stringCase; @@ -773,7 +772,7 @@ export class UnionInstantiationTransformer extends Transformer { return new UnionInstantiationTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; return other instanceof UnionInstantiationTransformer; } @@ -825,7 +824,7 @@ export class StringProducerTransformer extends ProducerTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; if (!(other instanceof StringProducerTransformer)) return false; return this.result === other.result; @@ -869,7 +868,7 @@ export class ParseStringTransformer extends ProducerTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; return other instanceof ParseStringTransformer; } @@ -903,7 +902,7 @@ export class StringifyTransformer extends ProducerTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; return other instanceof StringifyTransformer; } @@ -957,7 +956,7 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; return ( other instanceof MinMaxLengthCheckTransformer && @@ -1015,7 +1014,7 @@ export class MinMaxValueTransformer extends ProducerTransformer { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!super.equals(other)) return false; return ( other instanceof MinMaxValueTransformer && this.minimum === other.minimum && this.maximum === other.maximum @@ -1058,7 +1057,7 @@ export class Transformation { ); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!(other instanceof Transformation)) return false; return this._targetTypeRef === other._targetTypeRef && this.transformer.equals(other.transformer); } diff --git a/packages/quicktype-core/src/Type.ts b/packages/quicktype-core/src/Type.ts index 6184f712b..d5bab5cf2 100644 --- a/packages/quicktype-core/src/Type.ts +++ b/packages/quicktype-core/src/Type.ts @@ -112,7 +112,8 @@ export class TypeIdentity { public constructor( private readonly _kind: TypeKind, - private readonly _components: readonly any[] + // FIXME: strongly type this + private readonly _components: readonly unknown[] ) { let h = hashCodeInit; h = addHashCode(h, hashCodeOf(this._kind)); @@ -123,7 +124,7 @@ export class TypeIdentity { this._hashCode = h; } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!(other instanceof TypeIdentity)) return false; if (this._kind !== other._kind) return false; const n = this._components.length; @@ -197,7 +198,7 @@ export abstract class Type { return this.kind; } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!(other instanceof Type)) return false; return this.typeRef === other.typeRef; } @@ -434,7 +435,7 @@ export class GenericClassProperty { public readonly isOptional: boolean ) {} - public equals(other: any): boolean { + public equals(other: GenericClassProperty): boolean { if (!(other instanceof GenericClassProperty)) { return false; } diff --git a/packages/quicktype-core/src/TypeGraph.ts b/packages/quicktype-core/src/TypeGraph.ts index 98df9370f..3e229bd51 100644 --- a/packages/quicktype-core/src/TypeGraph.ts +++ b/packages/quicktype-core/src/TypeGraph.ts @@ -25,7 +25,7 @@ const indexMask = (1 << indexBits) - 1; const serialBits = 31 - indexBits; const serialMask = (1 << serialBits) - 1; -export function isTypeRef(x: any): x is TypeRef { +export function isTypeRef(x: unknown): x is TypeRef { return typeof x === "number"; } @@ -292,7 +292,7 @@ export class TypeGraph { return result; } - private setPrintOnRewrite(): void { + public setPrintOnRewrite(): void { this._printOnRewrite = true; } @@ -448,7 +448,7 @@ export class TypeGraph { return this._parents[t.index]; } - private printGraph(): void { + public printGraph(): void { const types = defined(this._types); for (let i = 0; i < types.length; i++) { const t = types[i]; diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index 07fdd4e65..f4ab36d34 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -131,7 +131,7 @@ export function isAnyOrNull(t: Type): boolean { // introduced. export function removeNullFromUnion( t: UnionType, - sortBy: boolean | ((t: Type) => any) = false + sortBy: boolean | ((t: Type) => string | number) = false ): [PrimitiveType | null, ReadonlySet] { function sort(s: ReadonlySet): ReadonlySet { if (sortBy === false) return s; diff --git a/packages/quicktype-core/src/attributes/AccessorNames.ts b/packages/quicktype-core/src/attributes/AccessorNames.ts index cb19ca59e..01621a65b 100644 --- a/packages/quicktype-core/src/attributes/AccessorNames.ts +++ b/packages/quicktype-core/src/attributes/AccessorNames.ts @@ -168,12 +168,12 @@ export function unionMemberName(u: UnionType, member: Type, language: string): [ return [first, isFixed]; } -function isAccessorEntry(x: any): x is string | { [language: string]: string } { +function isAccessorEntry(x: unknown): x is string | { [language: string]: string } { if (typeof x === "string") { return true; } - return isStringMap(x, (v: any): v is string => typeof v === "string"); + return isStringMap(x, (v: unknown): v is string => typeof v === "string"); } function makeAccessorEntry(ae: string | { [language: string]: string }): AccessorEntry { @@ -181,7 +181,7 @@ function makeAccessorEntry(ae: string | { [language: string]: string }): Accesso return mapFromObject(ae); } -export function makeAccessorNames(x: any): AccessorNames { +export function makeAccessorNames(x: unknown): AccessorNames { // FIXME: Do proper error reporting const stringMap = checkStringMap(x, isAccessorEntry); return mapMap(mapFromObject(stringMap), makeAccessorEntry); diff --git a/packages/quicktype-core/src/attributes/Description.ts b/packages/quicktype-core/src/attributes/Description.ts index 01022e7dd..a1f64efcd 100644 --- a/packages/quicktype-core/src/attributes/Description.ts +++ b/packages/quicktype-core/src/attributes/Description.ts @@ -123,8 +123,8 @@ export function descriptionAttributeProducer( } if (types.has("object") && typeof schema.properties === "object") { - const propertyDescriptions = mapFilterMap(mapFromObject(schema.properties), propSchema => { - if (typeof propSchema === "object") { + const propertyDescriptions = mapFilterMap(mapFromObject(schema.properties), propSchema => { + if (propSchema && typeof propSchema === "object" && "description" in propSchema) { const desc = propSchema.description; if (typeof desc === "string") { return new Set([desc]); diff --git a/packages/quicktype-core/src/attributes/StringTypes.ts b/packages/quicktype-core/src/attributes/StringTypes.ts index 343eeebe0..ae8539a24 100644 --- a/packages/quicktype-core/src/attributes/StringTypes.ts +++ b/packages/quicktype-core/src/attributes/StringTypes.ts @@ -109,7 +109,7 @@ export class StringTypes { return new StringTypes(this.cases, new Set(kinds)); } - public equals(other: any): boolean { + public equals(other: T): boolean { if (!(other instanceof StringTypes)) return false; return areEqual(this.cases, other.cases) && areEqual(this.transformations, other.transformations); } diff --git a/packages/quicktype-core/src/attributes/TypeAttributes.ts b/packages/quicktype-core/src/attributes/TypeAttributes.ts index 164f9878d..e8a3a61cd 100644 --- a/packages/quicktype-core/src/attributes/TypeAttributes.ts +++ b/packages/quicktype-core/src/attributes/TypeAttributes.ts @@ -86,7 +86,7 @@ export class TypeAttributeKind { return mapFilter(a, (_, k) => k !== this); } - public equals(other: any): boolean { + public equals(other: TypeAttributeKind): boolean { if (!(other instanceof TypeAttributeKind)) { return false; } @@ -99,6 +99,8 @@ export class TypeAttributeKind { } } +// FIXME: strongly type this +// eslint-disable-next-line @typescript-eslint/no-explicit-any export type TypeAttributes = ReadonlyMap, any>; export const emptyTypeAttributes: TypeAttributes = new Map(); @@ -126,6 +128,8 @@ export function combineTypeAttributes( const attributesByKind = mapTranspose(attributeArray); + // FIXME: strongly type this + // eslint-disable-next-line @typescript-eslint/no-explicit-any function combine(attrs: any[], kind: TypeAttributeKind): any { assert(attrs.length > 0, "Cannot combine zero type attributes"); if (attrs.length === 1) return attrs[0]; diff --git a/packages/quicktype-core/src/input/CompressedJSON.ts b/packages/quicktype-core/src/input/CompressedJSON.ts index 2aa3355cf..15e6122d0 100644 --- a/packages/quicktype-core/src/input/CompressedJSON.ts +++ b/packages/quicktype-core/src/input/CompressedJSON.ts @@ -255,7 +255,7 @@ export abstract class CompressedJSON { this._ctx = this._contextStack.pop(); } - public equals(other: any): boolean { + public equals(other: CompressedJSON): boolean { return this === other; } @@ -319,7 +319,7 @@ export class CompressedJSONFromString extends CompressedJSON { this.pushObjectContext(); for (const key of Object.getOwnPropertyNames(json)) { this.setPropertyKey(key); - this.process((json as any)[key]); + this.process(json[key as keyof typeof json]); } this.finishObject(); diff --git a/packages/quicktype-core/src/input/Inputs.ts b/packages/quicktype-core/src/input/Inputs.ts index 031d84ead..be10e48d2 100644 --- a/packages/quicktype-core/src/input/Inputs.ts +++ b/packages/quicktype-core/src/input/Inputs.ts @@ -166,6 +166,7 @@ export function jsonInputForTargetLanguage( export class InputData { // FIXME: Make into a Map, indexed by kind. + // eslint-disable-next-line @typescript-eslint/no-explicit-any private _inputs: Set> = new Set(); protected addInput(input: Input): void { diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index 03ce2ea6c..0938bae22 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -78,25 +78,27 @@ function keyOrIndex(pe: PathElement): string | undefined { function pathElementEquals(a: PathElement, b: PathElement): boolean { if (a.kind !== b.kind) return false; - switch (a.kind) { - case PathElementKind.Type: - return a.index === (b as any).index; - case PathElementKind.KeyOrIndex: - return a.key === (b as any).key; - default: - return true; + + if (a.kind === PathElementKind.Type && b.kind === PathElementKind.Type) { + return a.index === b.index; } + + if (a.kind === PathElementKind.KeyOrIndex && b.kind === PathElementKind.KeyOrIndex) { + return a.key === b.key; + } + + return true; } function withRef(refOrLoc: Ref | (() => Ref) | Location): { ref: Ref }; function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): T & { ref: Ref }; -function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): any { +function withRef(refOrLoc: Ref | (() => Ref) | Location, props?: T): unknown { const ref = typeof refOrLoc === "function" ? refOrLoc() : refOrLoc instanceof Ref ? refOrLoc : refOrLoc.canonicalRef; return Object.assign({ ref }, props ?? {}); } -function checkJSONSchemaObject(x: any, refOrLoc: Ref | (() => Ref)): StringMap { +function checkJSONSchemaObject(x: unknown, refOrLoc: Ref | (() => Ref)): StringMap { if (Array.isArray(x)) { return messageError("SchemaArrayIsInvalidSchema", withRef(refOrLoc)); } @@ -112,7 +114,7 @@ function checkJSONSchemaObject(x: any, refOrLoc: Ref | (() => Ref)): StringMap { return x; } -function checkJSONSchema(x: any, refOrLoc: Ref | (() => Ref)): JSONSchema { +function checkJSONSchema(x: unknown, refOrLoc: Ref | (() => Ref)): JSONSchema { if (typeof x === "boolean") return x; return checkJSONSchemaObject(x, refOrLoc); } @@ -293,7 +295,7 @@ export class Ref { return address + "#" + this.path.map(elementToString).join("/"); } - private lookup(local: any, path: readonly PathElement[], root: JSONSchema): JSONSchema { + private lookup(local: unknown, path: readonly PathElement[], root: JSONSchema): JSONSchema { const refMaker = () => new Ref(this.addressURI, path); const first = path[0]; if (first === undefined) { @@ -338,7 +340,7 @@ export class Ref { return this.lookup(root, this.path, root); } - public equals(other: any): boolean { + public equals(other: R): boolean { if (!(other instanceof Ref)) return false; if (this.addressURI !== undefined && other.addressURI !== undefined) { if (!this.addressURI.equals(other.addressURI)) return false; @@ -389,7 +391,7 @@ class Location { this.virtualRef = virtualRef ?? canonicalRef; } - public updateWithID(id: any) { + public updateWithID(id: string | unknown) { if (typeof id !== "string") return this; const parsed = Ref.parse(id); const virtual = this.haveID ? parsed.resolveAgainst(this.virtualRef) : parsed; @@ -424,7 +426,7 @@ class Canonizer { public constructor(private readonly _ctx: RunContext) {} - private addIDs(schema: any, loc: Location) { + private addIDs(schema: unknown, loc: Location) { if (schema === null) return; if (Array.isArray(schema)) { for (let i = 0; i < schema.length; i++) { @@ -439,7 +441,7 @@ class Canonizer { } const locWithoutID = loc; - const maybeID = schema.$id; + const maybeID = "$id" in schema ? schema.$id : undefined; if (typeof maybeID === "string") { loc = loc.updateWithID(maybeID); } @@ -453,11 +455,11 @@ class Canonizer { } for (const property of Object.getOwnPropertyNames(schema)) { - this.addIDs(schema[property], loc.push(property)); + this.addIDs(schema[property as keyof typeof schema], loc.push(property)); } } - public addSchema(schema: any, address: string): boolean { + public addSchema(schema: unknown, address: string): boolean { if (this._schemaAddressesAdded.has(address)) return false; this.addIDs(schema, new Location(Ref.root(address), Ref.root(undefined))); @@ -479,7 +481,7 @@ class Canonizer { } } -function checkTypeList(typeOrTypes: any, loc: Location): ReadonlySet { +function checkTypeList(typeOrTypes: string | string[], loc: Location): ReadonlySet { let set: Set; if (typeof typeOrTypes === "string") { set = new Set([typeOrTypes]); @@ -508,7 +510,7 @@ function checkTypeList(typeOrTypes: any, loc: Location): ReadonlySet { return set; } -function checkRequiredArray(arr: any, loc: Location): string[] { +function checkRequiredArray(arr: string[], loc: Location): string[] { if (!Array.isArray(arr)) { return messageError("SchemaRequiredMustBeStringOrStringArray", withRef(loc, { actual: arr })); } @@ -678,7 +680,7 @@ async function addTypesInSchema( attributes: TypeAttributes, properties: StringMap, requiredArray: string[], - additionalProperties: any, + additionalProperties: unknown, sortKey: (k: string) => number | string = (k: string) => k.toLowerCase() ): Promise { const required = new Set(requiredArray); @@ -734,16 +736,16 @@ async function addTypesInSchema( } if (enumArray !== undefined) { - let predicate: (x: any) => boolean; + let predicate: (x: unknown) => boolean; switch (name) { case "null": - predicate = (x: any) => x === null; + predicate = (x: unknown) => x === null; break; case "integer": - predicate = (x: any) => typeof x === "number" && x === Math.floor(x); + predicate = (x: unknown) => typeof x === "number" && x === Math.floor(x); break; default: - predicate = (x: any) => typeof x === name; + predicate = (x: unknown) => typeof x === name; break; } @@ -916,13 +918,12 @@ async function addTypesInSchema( return await makeObject(loc, objectAttributes, properties, required, additionalProperties, orderKey); } - async function makeTypesFromCases(cases: any, kind: string): Promise { + async function makeTypesFromCases(cases: unknown[], kind: string): Promise { const kindLoc = loc.push(kind); if (!Array.isArray(cases)) { return messageError("SchemaSetOperationCasesIsNotArray", withRef(kindLoc, { operation: kind, cases })); } - // FIXME: This cast shouldn't be necessary, but TypeScript forces our hand. return await arrayMapSync(cases, async (t, index) => { const caseLoc = kindLoc.push(index.toString()); return await toType( @@ -936,7 +937,7 @@ async function addTypesInSchema( const intersectionType = typeBuilder.getUniqueIntersectionType(typeAttributes, undefined); setTypeForLocation(loc, intersectionType); - async function convertOneOrAnyOf(cases: any, kind: string): Promise { + async function convertOneOrAnyOf(cases: unknown[], kind: string): Promise { const typeRefs = await makeTypesFromCases(cases, kind); let unionAttributes = makeTypeAttributesInferred(typeAttributes); if (kind === "oneOf") { @@ -971,7 +972,7 @@ async function addTypesInSchema( const needStringEnum = includedTypes.has("string") && enumArray !== undefined && - enumArray.find((x: any) => typeof x === "string") !== undefined; + enumArray.find(x => typeof x === "string") !== undefined; const needUnion = typeSet !== undefined || schema.properties !== undefined || @@ -1007,9 +1008,7 @@ async function addTypesInSchema( ); if (needStringEnum || isConst) { - const cases = isConst - ? [schema.const] - : ((enumArray as any[]).filter(x => typeof x === "string") as string[]); + const cases = isConst ? [schema.const] : enumArray?.filter(x => typeof x === "string") ?? []; unionTypes.push(typeBuilder.getStringType(stringAttributes, StringTypes.fromCases(cases))); } else if (includedTypes.has("string")) { unionTypes.push(makeStringType(stringAttributes)); diff --git a/packages/quicktype-core/src/input/PostmanCollection.ts b/packages/quicktype-core/src/input/PostmanCollection.ts index ce554ffb5..fd191a8c6 100644 --- a/packages/quicktype-core/src/input/PostmanCollection.ts +++ b/packages/quicktype-core/src/input/PostmanCollection.ts @@ -2,7 +2,7 @@ import { parseJSON } from "../support/Support"; import { type JSONSourceData } from "./Inputs"; -function isValidJSON (s: string): boolean { +function isValidJSON(s: string): boolean { try { JSON.parse(s); return true; @@ -11,14 +11,15 @@ function isValidJSON (s: string): boolean { } } -export function sourcesFromPostmanCollection ( +export function sourcesFromPostmanCollection( collectionJSON: string, - collectionJSONAddress?: string, -): { description: string | undefined, sources: Array>, } { + collectionJSONAddress?: string +): { description: string | undefined; sources: Array> } { const sources: Array> = []; const descriptions: string[] = []; - function processCollection (c: any): void { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function processCollection(c: any): void { if (typeof c !== "object") return; if (Array.isArray(c.item)) { for (const item of c.item) { diff --git a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts index 063f2794e..846f6a0a5 100644 --- a/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts +++ b/packages/quicktype-core/src/input/io/get-stream/buffer-stream.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { PassThrough } from "readable-stream"; import { type Options } from "."; diff --git a/packages/quicktype-core/src/input/io/get-stream/index.ts b/packages/quicktype-core/src/input/io/get-stream/index.ts index 4ae2d3ae7..6cf051d51 100644 --- a/packages/quicktype-core/src/input/io/get-stream/index.ts +++ b/packages/quicktype-core/src/input/io/get-stream/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { type Readable } from "readable-stream"; import bufferStream from "./buffer-stream"; diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index 0bfd40f57..88e78f414 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -13,7 +13,7 @@ * To print json string from json data use the following: char * string = cJSON_Print(); * To delete json data use the following: cJSON_Delete(); * - * TODO list for futur enhancements: + * TODO list for future enhancements: * - Management of Class, Union and TopLevel should be mutualized to reduce code size and to permit Union and TopLevel having recursive Array/Map * - Types check should be added to verify unwanted inputs (for example a Number passed while a String is expected, etc) * - Constraints should be implemented (verification of Enum values, min/max values for Numbers and min/max length for Strings, regex) @@ -40,6 +40,7 @@ import { import { assert, assertNever, defined, numberEnumValues, panic } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { ArrayType, ClassType, EnumType, MapType, type Type, type TypeKind, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; /* Naming styles */ @@ -142,7 +143,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * Return cJSON generator options * @return cJSON generator options array */ - protected getOptions(): Array> { + protected getOptions(): Array> { return [ cJSONOptions.typeSourceStyle, cJSONOptions.typeIntegerSize, @@ -177,7 +178,7 @@ export class CJSONTargetLanguage extends TargetLanguage { * @param untypedOptionValues * @return cJSON renderer */ - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): CJSONRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): CJSONRenderer { return new CJSONRenderer(this, renderContext, getOptionValues(cJSONOptions, untypedOptionValues)); } } diff --git a/packages/quicktype-core/src/language/CPlusPlus.ts b/packages/quicktype-core/src/language/CPlusPlus.ts index b75f834f6..c787a8778 100644 --- a/packages/quicktype-core/src/language/CPlusPlus.ts +++ b/packages/quicktype-core/src/language/CPlusPlus.ts @@ -50,6 +50,7 @@ import { type TypeKind, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableTypes, isNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; @@ -143,7 +144,7 @@ export class CPlusPlusTargetLanguage extends TargetLanguage { super(displayName, names, extension); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ cPlusPlusOptions.justTypes, cPlusPlusOptions.namespace, @@ -169,21 +170,18 @@ export class CPlusPlusTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): CPlusPlusRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): CPlusPlusRenderer { return new CPlusPlusRenderer(this, renderContext, getOptionValues(cPlusPlusOptions, untypedOptionValues)); } } function constraintsForType(t: Type): -| { - minMax?: MinMaxConstraint; - minMaxLength?: MinMaxConstraint; - pattern?: string; -} -| undefined { + | { + minMax?: MinMaxConstraint; + minMaxLength?: MinMaxConstraint; + pattern?: string; + } + | undefined { const minMax = minMaxValueForType(t); const minMaxLength = minMaxLengthForType(t); const pattern = patternForType(t); @@ -1375,11 +1373,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { pattern === undefined ? this._nulloptType : [ - this._stringType.getType(), - "(", - this._stringType.createStringLiteral([stringEscape(pattern)]), - ")" - ], + this._stringType.getType(), + "(", + this._stringType.createStringLiteral([stringEscape(pattern)]), + ")" + ], ")" ]); }); @@ -2646,11 +2644,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { protected gatherUserNamespaceForwardDecls(): Sourcelike[] { return this.gatherSource(() => { - this.forEachObject("leading-and-interposing", (_: any, className: Name) => + this.forEachObject("leading-and-interposing", (_: unknown, className: Name) => this.emitClassHeaders(className) ); - this.forEachEnum("leading-and-interposing", (_: any, enumName: Name) => this.emitEnumHeaders(enumName)); + this.forEachEnum("leading-and-interposing", (_: unknown, enumName: Name) => this.emitEnumHeaders(enumName)); }); } diff --git a/packages/quicktype-core/src/language/CSharp.ts b/packages/quicktype-core/src/language/CSharp.ts index 54c0de48d..159dab900 100644 --- a/packages/quicktype-core/src/language/CSharp.ts +++ b/packages/quicktype-core/src/language/CSharp.ts @@ -58,6 +58,7 @@ import { UnionType } from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export enum Framework { @@ -212,7 +213,7 @@ export class CSharpTargetLanguage extends TargetLanguage { super("C#", ["cs", "csharp"], "cs"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ cSharpOptions.framework, cSharpOptions.namespace, @@ -254,10 +255,7 @@ export class CSharpTargetLanguage extends TargetLanguage { return need !== "none" && need !== "nullable"; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): ConvenienceRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { const options = getOptionValues(cSharpOptions, untypedOptionValues); switch (options.framework) { diff --git a/packages/quicktype-core/src/language/Crystal.ts b/packages/quicktype-core/src/language/Crystal.ts index 1376c488c..3b06122af 100644 --- a/packages/quicktype-core/src/language/Crystal.ts +++ b/packages/quicktype-core/src/language/Crystal.ts @@ -20,6 +20,7 @@ import { } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; import { type ClassType, type EnumType, type Type, type UnionType } from "../Type"; +import { type FixMeOptionsAnyType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export class CrystalTargetLanguage extends TargetLanguage { @@ -35,7 +36,7 @@ export class CrystalTargetLanguage extends TargetLanguage { return " "; } - protected getOptions(): Array> { + protected getOptions(): Array> { return []; } } diff --git a/packages/quicktype-core/src/language/Dart.ts b/packages/quicktype-core/src/language/Dart.ts index 71360e7d1..59476c982 100644 --- a/packages/quicktype-core/src/language/Dart.ts +++ b/packages/quicktype-core/src/language/Dart.ts @@ -33,6 +33,7 @@ import { type UnionType } from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; export const dartOptions = { @@ -64,7 +65,7 @@ export class DartTargetLanguage extends TargetLanguage { super("Dart", ["dart"], "dart"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ dartOptions.nullSafety, dartOptions.justTypes, @@ -91,7 +92,7 @@ export class DartTargetLanguage extends TargetLanguage { return mapping; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): DartRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): DartRenderer { const options = getOptionValues(dartOptions, untypedOptionValues); return new DartRenderer(this, renderContext, options); } diff --git a/packages/quicktype-core/src/language/Elm.ts b/packages/quicktype-core/src/language/Elm.ts index 426764b63..ced7837b4 100644 --- a/packages/quicktype-core/src/language/Elm.ts +++ b/packages/quicktype-core/src/language/Elm.ts @@ -29,6 +29,7 @@ import { import { defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { type ClassProperty, type ClassType, type EnumType, type Type, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion } from "../TypeUtils"; export const elmOptions = { @@ -46,7 +47,7 @@ export class ElmTargetLanguage extends TargetLanguage { super("Elm", ["elm"], "elm"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [elmOptions.justTypes, elmOptions.moduleName, elmOptions.useList]; } @@ -58,7 +59,7 @@ export class ElmTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): ElmRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ElmRenderer { return new ElmRenderer(this, renderContext, getOptionValues(elmOptions, untypedOptionValues)); } } diff --git a/packages/quicktype-core/src/language/Golang.ts b/packages/quicktype-core/src/language/Golang.ts index 277c083f5..9a2081af6 100644 --- a/packages/quicktype-core/src/language/Golang.ts +++ b/packages/quicktype-core/src/language/Golang.ts @@ -19,6 +19,7 @@ import { import { assert, defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { type ClassProperty, type ClassType, type EnumType, type Type, type TypeKind, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export const goOptions = { @@ -39,7 +40,7 @@ export class GoTargetLanguage extends TargetLanguage { super("Go", ["go", "golang"], "go"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ goOptions.justTypes, goOptions.justTypesAndPackage, @@ -64,7 +65,7 @@ export class GoTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): GoRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): GoRenderer { return new GoRenderer(this, renderContext, getOptionValues(goOptions, untypedOptionValues)); } diff --git a/packages/quicktype-core/src/language/Haskell.ts b/packages/quicktype-core/src/language/Haskell.ts index 7b7b7ef49..16cd16a35 100644 --- a/packages/quicktype-core/src/language/Haskell.ts +++ b/packages/quicktype-core/src/language/Haskell.ts @@ -26,6 +26,7 @@ import { } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion } from "../TypeUtils"; export const haskellOptions = { @@ -42,7 +43,7 @@ export class HaskellTargetLanguage extends TargetLanguage { super("Haskell", ["haskell"], "haskell"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [haskellOptions.justTypes, haskellOptions.moduleName, haskellOptions.useList]; } @@ -54,10 +55,7 @@ export class HaskellTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): HaskellRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): HaskellRenderer { return new HaskellRenderer(this, renderContext, getOptionValues(haskellOptions, untypedOptionValues)); } } diff --git a/packages/quicktype-core/src/language/JSONSchema.ts b/packages/quicktype-core/src/language/JSONSchema.ts index ab7e85b1e..978906075 100644 --- a/packages/quicktype-core/src/language/JSONSchema.ts +++ b/packages/quicktype-core/src/language/JSONSchema.ts @@ -22,6 +22,7 @@ import { transformedStringTypeTargetTypeKindsMap } from "../Type"; import { type StringTypeMapping, getNoStringTypeMapping } from "../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchTypeExhaustive } from "../TypeUtils"; export class JSONSchemaTargetLanguage extends TargetLanguage { @@ -29,7 +30,7 @@ export class JSONSchemaTargetLanguage extends TargetLanguage { super("JSON Schema", ["schema", "json-schema"], "schema"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return []; } @@ -45,10 +46,7 @@ export class JSONSchemaTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - _untypedOptionValues: { [name: string]: any } - ): JSONSchemaRenderer { + protected makeRenderer(renderContext: RenderContext, _untypedOptionValues: FixMeOptionsType): JSONSchemaRenderer { return new JSONSchemaRenderer(this, renderContext); } } @@ -72,6 +70,7 @@ function jsonNameStyle(original: string): string { } interface Schema { + // eslint-disable-next-line @typescript-eslint/no-explicit-any [name: string]: any; } @@ -121,7 +120,7 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { } private schemaForType(t: Type): Schema { - const schema = matchTypeExhaustive<{ [name: string]: any }>( + const schema = matchTypeExhaustive( t, _noneType => { return panic("none type should have been replaced"); diff --git a/packages/quicktype-core/src/language/Java.ts b/packages/quicktype-core/src/language/Java.ts index 7080be5e9..6954a13f4 100644 --- a/packages/quicktype-core/src/language/Java.ts +++ b/packages/quicktype-core/src/language/Java.ts @@ -40,6 +40,7 @@ import { type TypeKind, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export const javaOptions = { @@ -74,7 +75,7 @@ export class JavaTargetLanguage extends TargetLanguage { super("Java", ["java"], "java"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ javaOptions.useList, javaOptions.justTypes, @@ -90,7 +91,7 @@ export class JavaTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): JavaRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): JavaRenderer { const options = getOptionValues(javaOptions, untypedOptionValues); if (options.justTypes) { return new JavaRenderer(this, renderContext, options); diff --git a/packages/quicktype-core/src/language/JavaScript.ts b/packages/quicktype-core/src/language/JavaScript.ts index 0cf29f4ff..ff435edc1 100644 --- a/packages/quicktype-core/src/language/JavaScript.ts +++ b/packages/quicktype-core/src/language/JavaScript.ts @@ -28,6 +28,7 @@ import { type Type } from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableSingleNamedType, matchType } from "../TypeUtils"; import { isES3IdentifierPart, isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; @@ -69,7 +70,7 @@ export class JavaScriptTargetLanguage extends TargetLanguage { super(displayName, names, extension); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ javaScriptOptions.runtimeTypecheck, javaScriptOptions.runtimeTypecheckIgnoreUnknownProperties, @@ -95,10 +96,7 @@ export class JavaScriptTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): JavaScriptRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): JavaScriptRenderer { return new JavaScriptRenderer(this, renderContext, getOptionValues(javaScriptOptions, untypedOptionValues)); } } diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts index cbdd4e6ad..a2ae5b40c 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts @@ -17,7 +17,8 @@ import { utf16StringEscape } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type } from "../Type"; +import { type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type, ArrayType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableSingleNamedType, matchType } from "../TypeUtils"; import { legalizeName } from "./JavaScript"; @@ -38,7 +39,7 @@ export const javaScriptPropTypesOptions = { }; export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { + protected getOptions(): Array> { return [javaScriptPropTypesOptions.acronymStyle, javaScriptPropTypesOptions.converters]; } @@ -52,7 +53,7 @@ export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: FixMeOptionsType ): JavaScriptPropTypesRenderer { return new JavaScriptPropTypesRenderer( this, @@ -271,7 +272,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { } else { if (type.kind === "array") { this.ensureBlankLine(); - this.emitExport(name, ["PropTypes.arrayOf(", this.typeMapTypeFor((type as any).items), ")"]); + this.emitExport(name, ["PropTypes.arrayOf(", this.typeMapTypeFor((type as ArrayType).items), ")"]); } else { this.ensureBlankLine(); this.emitExport(name, ["_", name]); diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts index f6fcebb04..06de856a7 100644 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ b/packages/quicktype-core/src/language/Kotlin.ts @@ -36,6 +36,7 @@ import { type Type, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export enum Framework { @@ -66,7 +67,7 @@ export class KotlinTargetLanguage extends TargetLanguage { super("Kotlin", ["kotlin"], "kt"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [kotlinOptions.framework, kotlinOptions.acronymStyle, kotlinOptions.packageName]; } @@ -78,10 +79,7 @@ export class KotlinTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): ConvenienceRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { const options = getOptionValues(kotlinOptions, untypedOptionValues); switch (options.framework) { diff --git a/packages/quicktype-core/src/language/Objective-C.ts b/packages/quicktype-core/src/language/Objective-C.ts index f6d3e47d5..00d678f30 100644 --- a/packages/quicktype-core/src/language/Objective-C.ts +++ b/packages/quicktype-core/src/language/Objective-C.ts @@ -29,6 +29,7 @@ import { import { assert, defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, Type, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { isAnyOrNull, matchType, nullableFromUnion } from "../TypeUtils"; export type MemoryAttribute = "assign" | "strong" | "copy"; @@ -57,7 +58,7 @@ export class ObjectiveCTargetLanguage extends TargetLanguage { super("Objective-C", ["objc", "objective-c", "objectivec"], "m"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ objcOptions.justTypes, objcOptions.classPrefix, @@ -67,10 +68,7 @@ export class ObjectiveCTargetLanguage extends TargetLanguage { ]; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): ObjectiveCRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ObjectiveCRenderer { return new ObjectiveCRenderer(this, renderContext, getOptionValues(objcOptions, untypedOptionValues)); } } diff --git a/packages/quicktype-core/src/language/Php.ts b/packages/quicktype-core/src/language/Php.ts index fd0888dcf..f3b07ef2f 100644 --- a/packages/quicktype-core/src/language/Php.ts +++ b/packages/quicktype-core/src/language/Php.ts @@ -25,6 +25,7 @@ import { import { defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; export const phpOptions = { @@ -40,7 +41,7 @@ export class PhpTargetLanguage extends TargetLanguage { super("PHP", ["php"], "php"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return _.values(phpOptions); } @@ -48,7 +49,7 @@ export class PhpTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): PhpRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PhpRenderer { const options = getOptionValues(phpOptions, untypedOptionValues); return new PhpRenderer(this, renderContext, options); } diff --git a/packages/quicktype-core/src/language/Pike.ts b/packages/quicktype-core/src/language/Pike.ts index dc57a3fc4..fd2a8b2b9 100644 --- a/packages/quicktype-core/src/language/Pike.ts +++ b/packages/quicktype-core/src/language/Pike.ts @@ -6,6 +6,7 @@ import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } import { isLetterOrUnderscoreOrDigit, legalizeCharacters, makeNameStyle, stringEscape } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; import { ArrayType, type ClassType, type EnumType, MapType, PrimitiveType, type Type, type UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export const pikeOptions = {}; @@ -75,7 +76,7 @@ export class PikeTargetLanguage extends TargetLanguage { super("Pike", ["pike", "pikelang"], "pmod"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return []; } diff --git a/packages/quicktype-core/src/language/Python.ts b/packages/quicktype-core/src/language/Python.ts index b6092a9d1..1066fcd11 100644 --- a/packages/quicktype-core/src/language/Python.ts +++ b/packages/quicktype-core/src/language/Python.ts @@ -48,6 +48,7 @@ import { UnionType } from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; const forbiddenTypeNames = [ @@ -130,7 +131,7 @@ export const pythonOptions = { }; export class PythonTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { + protected getOptions(): Array> { return [pythonOptions.features, pythonOptions.justTypes, pythonOptions.nicePropertyNames]; } @@ -162,7 +163,7 @@ export class PythonTargetLanguage extends TargetLanguage { return t.kind === "integer-string" || t.kind === "bool-string"; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): PythonRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PythonRenderer { const options = getOptionValues(pythonOptions, untypedOptionValues); if (options.justTypes) { return new PythonRenderer(this, renderContext, options); diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust.ts index f73a67f7b..2ffa07689 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust.ts @@ -23,6 +23,7 @@ import { import { defined } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { type ClassType, type EnumType, type Type, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export enum Density { @@ -112,7 +113,7 @@ const namingStyles: Record = { }; export class RustTargetLanguage extends TargetLanguage { - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): RustRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): RustRenderer { return new RustRenderer(this, renderContext, getOptionValues(rustOptions, untypedOptionValues)); } @@ -120,7 +121,7 @@ export class RustTargetLanguage extends TargetLanguage { super("Rust", ["rust", "rs", "rustlang"], "rs"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ rustOptions.density, rustOptions.visibility, @@ -346,7 +347,7 @@ export class RustRenderer extends ConvenienceRenderer { ); } - private breakCycle(t: Type, withIssues: boolean): any { + private breakCycle(t: Type, withIssues: boolean): Sourcelike { const rustType = this.rustType(t, withIssues); const isCycleBreaker = this.isCycleBreakerType(t); diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts index a736ecada..38a7cd451 100644 --- a/packages/quicktype-core/src/language/Scala3.ts +++ b/packages/quicktype-core/src/language/Scala3.ts @@ -27,6 +27,7 @@ import { type Type, type UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export enum Framework { @@ -745,7 +746,7 @@ export class Scala3TargetLanguage extends TargetLanguage { super("Scala3", ["scala3"], "scala"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [scala3Options.framework, scala3Options.packageName]; } @@ -757,10 +758,7 @@ export class Scala3TargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): ConvenienceRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { const options = getOptionValues(scala3Options, untypedOptionValues); switch (options.framework) { diff --git a/packages/quicktype-core/src/language/Smithy4s.ts b/packages/quicktype-core/src/language/Smithy4s.ts index 24ba6b028..2abe6f27f 100644 --- a/packages/quicktype-core/src/language/Smithy4s.ts +++ b/packages/quicktype-core/src/language/Smithy4s.ts @@ -27,6 +27,7 @@ import { type Type, type UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchCompoundType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export enum Framework { @@ -529,7 +530,7 @@ export class SmithyTargetLanguage extends TargetLanguage { super("Smithy", ["Smithy"], "smithy"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [SmithyOptions.framework, SmithyOptions.packageName]; } @@ -541,10 +542,7 @@ export class SmithyTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): ConvenienceRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { const options = getOptionValues(SmithyOptions, untypedOptionValues); switch (options.framework) { diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift.ts index 627218116..d46f56780 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift.ts @@ -47,6 +47,7 @@ import { type UnionType } from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; const MAX_SAMELINE_PROPERTIES = 4; @@ -141,7 +142,7 @@ export class SwiftTargetLanguage extends TargetLanguage { super("Swift", ["swift", "swift4"], "swift"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [ swiftOptions.justTypes, swiftOptions.useClasses, @@ -177,7 +178,7 @@ export class SwiftTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): SwiftRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): SwiftRenderer { return new SwiftRenderer(this, renderContext, getOptionValues(swiftOptions, untypedOptionValues)); } diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts index 9db2d827a..d288fea9a 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts @@ -19,6 +19,7 @@ import { import { panic } from "../support/Support"; import { TargetLanguage } from "../TargetLanguage"; import { ArrayType, type ClassProperty, EnumType, MapType, type ObjectType, type Type } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType } from "../TypeUtils"; import { legalizeName } from "./JavaScript"; @@ -28,7 +29,7 @@ export const typeScriptEffectSchemaOptions = { }; export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { + protected getOptions(): Array> { return []; } @@ -42,7 +43,7 @@ export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage { protected makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: FixMeOptionsType ): TypeScriptEffectSchemaRenderer { return new TypeScriptEffectSchemaRenderer( this, diff --git a/packages/quicktype-core/src/language/TypeScriptFlow.ts b/packages/quicktype-core/src/language/TypeScriptFlow.ts index f63c2d473..a0f6216b3 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow.ts @@ -6,6 +6,7 @@ import { camelCase, utf16StringEscape } from "../support/Strings"; import { defined, panic } from "../support/Support"; import { type TargetLanguage } from "../TargetLanguage"; import { ArrayType, type ClassType, EnumType, type Type, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { isNamedType, matchType, nullableFromUnion } from "../TypeUtils"; import { @@ -41,7 +42,7 @@ const tsFlowTypeAnnotations = { }; export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetLanguage { - protected getOptions(): Array> { + protected getOptions(): Array> { return [ tsFlowOptions.justTypes, tsFlowOptions.nicePropertyNames, @@ -64,7 +65,7 @@ export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetL protected abstract makeRenderer( renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } + untypedOptionValues: FixMeOptionsType ): JavaScriptRenderer; } @@ -73,10 +74,7 @@ export class TypeScriptTargetLanguage extends TypeScriptFlowBaseTargetLanguage { super("TypeScript", ["typescript", "ts", "tsx"], "ts"); } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): TypeScriptRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): TypeScriptRenderer { return new TypeScriptRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); } } @@ -348,7 +346,7 @@ export class FlowTargetLanguage extends TypeScriptFlowBaseTargetLanguage { super("Flow", ["flow"], "js"); } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): FlowRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): FlowRenderer { return new FlowRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); } } diff --git a/packages/quicktype-core/src/language/TypeScriptZod.ts b/packages/quicktype-core/src/language/TypeScriptZod.ts index d52c4eff7..57a67d1d2 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod.ts @@ -30,6 +30,7 @@ import { type Type } from "../Type"; import { type StringTypeMapping } from "../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { matchType } from "../TypeUtils"; import { legalizeName } from "./JavaScript"; @@ -39,7 +40,7 @@ export const typeScriptZodOptions = { }; export class TypeScriptZodTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { + protected getOptions(): Array> { return []; } @@ -62,10 +63,7 @@ export class TypeScriptZodTargetLanguage extends TargetLanguage { return true; } - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: { [name: string]: any } - ): TypeScriptZodRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): TypeScriptZodRenderer { return new TypeScriptZodRenderer( this, renderContext, diff --git a/packages/quicktype-core/src/language/ruby/index.ts b/packages/quicktype-core/src/language/ruby/index.ts index 10abe40d6..feb6e7608 100644 --- a/packages/quicktype-core/src/language/ruby/index.ts +++ b/packages/quicktype-core/src/language/ruby/index.ts @@ -36,6 +36,7 @@ import { type Type, type UnionType } from "../../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; import * as keywords from "./keywords"; @@ -69,7 +70,7 @@ export class RubyTargetLanguage extends TargetLanguage { super("Ruby", ["ruby"], "rb"); } - protected getOptions(): Array> { + protected getOptions(): Array> { return [rubyOptions.justTypes, rubyOptions.strictness, rubyOptions.namespace]; } @@ -81,7 +82,7 @@ export class RubyTargetLanguage extends TargetLanguage { return " "; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): RubyRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): RubyRenderer { return new RubyRenderer(this, renderContext, getOptionValues(rubyOptions, untypedOptionValues)); } } diff --git a/packages/quicktype-core/src/support/Support.ts b/packages/quicktype-core/src/support/Support.ts index 31e78fd4b..3778ed3ed 100644 --- a/packages/quicktype-core/src/support/Support.ts +++ b/packages/quicktype-core/src/support/Support.ts @@ -5,19 +5,20 @@ import * as YAML from "yaml"; import { messageError } from "../Messages"; export interface StringMap { + // eslint-disable-next-line @typescript-eslint/no-explicit-any [name: string]: any; } -export function isStringMap(x: any): x is StringMap; -export function isStringMap(x: any, checkValue: (v: any) => v is T): x is { [name: string]: T }; -export function isStringMap(x: any, checkValue?: (v: any) => v is T): boolean { +export function isStringMap(x: unknown): x is StringMap; +export function isStringMap(x: unknown, checkValue: (v: unknown) => v is T): x is { [name: string]: T }; +export function isStringMap(x: unknown, checkValue?: (v: unknown) => v is T): boolean { if (typeof x !== "object" || Array.isArray(x) || x === null) { return false; } if (checkValue !== undefined) { for (const k of Object.getOwnPropertyNames(x)) { - const v = x[k]; + const v = x[k as keyof typeof x]; if (!checkValue(v)) { return false; } @@ -27,20 +28,27 @@ export function isStringMap(x: any, checkValue?: (v: any) => v is T): boolean return true; } -export function checkString(x: any): x is string { +export function checkString(x: unknown): x is string { return typeof x === "string"; } -export function checkStringMap(x: any): StringMap; -export function checkStringMap(x: any, checkValue: (v: any) => v is T): { [name: string]: T }; -export function checkStringMap(x: any, checkValue?: (v: any) => v is T): StringMap { - if (isStringMap(x, checkValue as any)) return x; +export function checkStringMap(x: unknown): StringMap; +export function checkStringMap(x: unknown, checkValue: (v: unknown) => v is T): { [name: string]: T }; +export function checkStringMap(x: unknown, checkValue?: (v: unknown) => v is T): StringMap { + if (checkValue && isStringMap(x, checkValue)) { + return x; + } + + if (isStringMap(x)) { + return x; + } + return panic(`Value must be an object, but is ${x}`); } -export function checkArray(x: any): any[]; -export function checkArray(x: any, checkItem: (v: any) => v is T): T[]; -export function checkArray(x: any, checkItem?: (v: any) => v is T): T[] { +export function checkArray(x: unknown): unknown[]; +export function checkArray(x: unknown, checkItem: (v: unknown) => v is T): T[]; +export function checkArray(x: unknown, checkItem?: (v: unknown) => v is T): T[] { if (!Array.isArray(x)) { return panic(`Value must be an array, but is ${x}`); } @@ -67,7 +75,7 @@ export function nonNull(x: T | null): T { } export function assertNever(x: never): never { - return messageError("InternalError", { message: `Unexpected object ${x as any}` }); + return messageError("InternalError", { message: `Unexpected object ${x}` }); } export function assert(condition: boolean, message = "Assertion failed"): void { @@ -102,12 +110,12 @@ export function repeatedCall(n: number, producer: () => T): T[] { return arr; } -export function errorMessage(e: any): string { +export function errorMessage(e: unknown): string { if (e instanceof Error) { return e.message; } - return e.toString(); + return (e as { toString: () => string }).toString(); } export function inflateBase64(encoded: string): string { @@ -115,7 +123,7 @@ export function inflateBase64(encoded: string): string { return pako.inflate(bytes, { to: "string" }); } -export function parseJSON(text: string, description: string, address = ""): any { +export function parseJSON(text: string, description: string, address = ""): unknown { try { // https://gist.github.com/pbakondy/f5045eff725193dad9c7 if (text.charCodeAt(0) === 0xfeff) { @@ -140,7 +148,8 @@ export function indentationString(level: number): string { return " ".repeat(level); } -export function numberEnumValues(e: { [key: string]: any }): number[] { +// FIXME: fix this enum iteration +export function numberEnumValues(e: Record): number[] { const result: number[] = []; for (const k of Object.keys(e)) { const v = e[k]; diff --git a/packages/quicktype-core/src/types.ts b/packages/quicktype-core/src/types.ts new file mode 100644 index 000000000..2b26cc2be --- /dev/null +++ b/packages/quicktype-core/src/types.ts @@ -0,0 +1,6 @@ +// FIXME: remove these when options are strongly types + +/* eslint-disable @typescript-eslint/no-explicit-any */ +export type FixMeOptionsType = Record; + +export type FixMeOptionsAnyType = any; diff --git a/packages/quicktype-graphql-input/src/index.ts b/packages/quicktype-graphql-input/src/index.ts index a6c1f53e2..1b18754ac 100644 --- a/packages/quicktype-graphql-input/src/index.ts +++ b/packages/quicktype-graphql-input/src/index.ts @@ -389,7 +389,7 @@ class GQLSchemaFromJSON implements GQLSchema { public readonly mutationType?: GQLType; - public constructor(json: any) { + public constructor(json: { data: GraphQLSchema }) { const schema: GraphQLSchema = json.data; if (schema.__schema.queryType.name === null) { @@ -498,7 +498,7 @@ class GQLSchemaFromJSON implements GQLSchema { function makeGraphQLQueryTypes( topLevelName: string, builder: TypeBuilder, - json: any, + json: { data: GraphQLSchema }, queryString: string ): Map { const schema = new GQLSchemaFromJSON(json); @@ -546,11 +546,13 @@ function makeGraphQLQueryTypes( export interface GraphQLSourceData { name: string; query: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any schema: any; } interface GraphQLTopLevel { query: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any schema: any; } diff --git a/src/CompressedJSONFromStream.ts b/src/CompressedJSONFromStream.ts index 40db6d87b..7d7be8830 100644 --- a/src/CompressedJSONFromStream.ts +++ b/src/CompressedJSONFromStream.ts @@ -23,14 +23,15 @@ export class CompressedJSONFromStream extends CompressedJSON { const combo = new Parser({ packKeys: true, packStrings: true }); combo.on("data", (item: { name: string; value: string | undefined }) => { if (typeof methodMap[item.name] === "string") { - (this as any)[methodMap[item.name]](item.value); + // @ts-expect-error FIXME: strongly type this + this[methodMap[item.name]](item.value); } }); const promise = new Promise((resolve, reject) => { combo.on("end", () => { resolve(this.finish()); }); - combo.on("error", (err: any) => { + combo.on("error", (err: unknown) => { reject(err); }); }); diff --git a/src/URLGrammar.ts b/src/URLGrammar.ts index 3ffdc26a8..3eaaaa1ca 100644 --- a/src/URLGrammar.ts +++ b/src/URLGrammar.ts @@ -1,6 +1,6 @@ import { checkArray, checkStringMap, panic } from "quicktype-core"; -function expand(json: any): string[] { +function expand(json: unknown): string[] { if (typeof json === "string") { return [json]; } @@ -22,7 +22,7 @@ function expand(json: any): string[] { return result; } - if (Object.prototype.hasOwnProperty.call(json, "oneOf")) { + if (typeof json === "object" && json && "oneOf" in json) { const options = checkArray(json.oneOf); const result: string[] = []; for (const j of options) { @@ -37,7 +37,7 @@ function expand(json: any): string[] { return panic(`Value is not a valid URL grammar: ${json}`); } -export function urlsFromURLGrammar(json: any): { [name: string]: string[] } { +export function urlsFromURLGrammar(json: unknown): { [name: string]: string[] } { const topLevelMap = checkStringMap(json); const results: { [name: string]: string[] } = {}; diff --git a/src/index.ts b/src/index.ts index 6804ef731..5006b0bde 100644 --- a/src/index.ts +++ b/src/index.ts @@ -60,6 +60,7 @@ const wordWrap: (s: string) => string = _wordwrap(90); export interface CLIOptions { // We use this to access the inference flags + // eslint-disable-next-line @typescript-eslint/no-explicit-any [option: string]: any; additionalSchema: string[]; allPropertiesOptional: boolean; @@ -199,7 +200,8 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr return messageError("DriverCannotMixJSONWithOtherSamples", { dir: dir }); } - const oneUnlessEmpty = (xs: any[]) => Math.sign(xs.length); + // FIXME: rewrite this to be clearer + const oneUnlessEmpty = (xs: TypeSource[]) => Math.sign(xs.length); if (oneUnlessEmpty(schemaSources) + oneUnlessEmpty(graphQLSources) > 1) { return messageError("DriverCannotMixNonJSONInputs", { dir: dir }); } @@ -594,6 +596,8 @@ export function parseCLIOptions(argv: string[], targetLanguage?: TargetLanguage) // according to each option definition's `renderer` field. If `partial` is false this // will throw if it encounters an unknown option. function parseOptions(definitions: OptionDefinition[], argv: string[], partial: boolean): Partial { + // FIXME: update this when options strongly typed + // eslint-disable-next-line @typescript-eslint/no-explicit-any let opts: { [key: string]: any }; try { opts = commandLineArgs(definitions, { argv, partial }); @@ -610,6 +614,7 @@ function parseOptions(definitions: OptionDefinition[], argv: string[], partial: } } + // eslint-disable-next-line @typescript-eslint/no-explicit-any const options: { [key: string]: any; rendererOptions: RendererOptions } = { rendererOptions: {} }; for (const o of definitions) { if (!hasOwnProperty(opts, o.name)) continue; From f0e76151fd7c86658db020f15327552a57434b08 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 20:26:24 -0700 Subject: [PATCH 24/80] fix misc errors --- packages/quicktype-core/src/Annotation.ts | 1 + packages/quicktype-core/src/TypeGraph.ts | 1 + packages/quicktype-core/src/TypeUtils.ts | 6 +----- packages/quicktype-core/src/UnifyClasses.ts | 2 ++ .../quicktype-core/src/input/JSONSchemaInput.ts | 2 +- .../quicktype-core/src/input/JSONSchemaStore.ts | 4 +++- .../src/input/io/get-stream/index.ts | 10 +++++----- packages/quicktype-core/src/language/CJSON.ts | 4 ++++ packages/quicktype-core/src/language/Dart.ts | 4 ++++ .../src/language/JavaScriptPropTypes.ts | 14 +++++++------- packages/quicktype-core/src/language/Kotlin.ts | 1 + packages/quicktype-core/src/language/Php.ts | 8 ++++---- packages/quicktype-core/src/language/Python.ts | 2 ++ packages/quicktype-core/src/language/Rust.ts | 6 +++++- packages/quicktype-core/src/language/Scala3.ts | 2 +- .../src/language/TypeScriptEffectSchema.ts | 16 ++++++++-------- .../quicktype-core/src/language/TypeScriptZod.ts | 3 +++ .../quicktype-core/src/rewrites/ExpandStrings.ts | 4 +++- .../src/rewrites/ResolveIntersections.ts | 3 ++- packages/quicktype-core/src/support/Strings.ts | 2 ++ src/CompressedJSONFromStream.ts | 2 +- 21 files changed, 61 insertions(+), 36 deletions(-) diff --git a/packages/quicktype-core/src/Annotation.ts b/packages/quicktype-core/src/Annotation.ts index 38cb82622..1b3a937bf 100644 --- a/packages/quicktype-core/src/Annotation.ts +++ b/packages/quicktype-core/src/Annotation.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line @typescript-eslint/no-extraneous-class export class AnnotationData {} export class IssueAnnotationData extends AnnotationData { diff --git a/packages/quicktype-core/src/TypeGraph.ts b/packages/quicktype-core/src/TypeGraph.ts index 3e229bd51..cdd8d5ea6 100644 --- a/packages/quicktype-core/src/TypeGraph.ts +++ b/packages/quicktype-core/src/TypeGraph.ts @@ -403,6 +403,7 @@ export class TypeGraph { } public rewriteFixedPoint(alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { + // eslint-disable-next-line @typescript-eslint/no-this-alias let graph: TypeGraph = this; for (;;) { const newGraph = this.rewrite( diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index f4ab36d34..f0136fc32 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -40,11 +40,7 @@ export function assertIsClass(t: Type): ClassType { } export function setOperationMembersRecursively( - setOperation: T, - combinationKind: CombinationKind | undefined -): [ReadonlySet, TypeAttributes]; -export function setOperationMembersRecursively( - setOperations: T[], + setOperations: T | T[], combinationKind: CombinationKind | undefined ): [ReadonlySet, TypeAttributes]; export function setOperationMembersRecursively( diff --git a/packages/quicktype-core/src/UnifyClasses.ts b/packages/quicktype-core/src/UnifyClasses.ts index f1e6ab3e0..8fe16817c 100644 --- a/packages/quicktype-core/src/UnifyClasses.ts +++ b/packages/quicktype-core/src/UnifyClasses.ts @@ -34,6 +34,8 @@ function getCliqueProperties( } } + // FIXME: refactor this + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < properties.length; i++) { let [name, types, isOptional] = properties[i]; const maybeProperty = o.getProperties().get(name); diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index 0938bae22..244e682be 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -208,7 +208,7 @@ export class Ref { } public push(...keys: string[]): Ref { - let ref: Ref = this; + let ref: Ref = { ...this }; for (const key of keys) { ref = ref.pushElement({ kind: PathElementKind.KeyOrIndex, key }); } diff --git a/packages/quicktype-core/src/input/JSONSchemaStore.ts b/packages/quicktype-core/src/input/JSONSchemaStore.ts index 4292bf08c..02d93e8e0 100644 --- a/packages/quicktype-core/src/input/JSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/JSONSchemaStore.ts @@ -25,7 +25,9 @@ export abstract class JSONSchemaStore { try { schema = await this.fetch(address); - } catch {} + } catch (e) { + // FIXME: handle or log this error + } if (schema === undefined) { if (debugPrint) { diff --git a/packages/quicktype-core/src/input/io/get-stream/index.ts b/packages/quicktype-core/src/input/io/get-stream/index.ts index 6cf051d51..3f1dcbc4b 100644 --- a/packages/quicktype-core/src/input/io/get-stream/index.ts +++ b/packages/quicktype-core/src/input/io/get-stream/index.ts @@ -50,15 +50,15 @@ export async function getStream(inputStream: Readable, opts: Options = {}) { }; }); - p.then(clean, clean); - - return await p.then(() => stream.getBufferedValue()); + return await p.then(clean, clean).then(() => stream.getBufferedValue()); } +// FIXME: should these be async ? export function buffer(stream: Readable, opts: Options = {}) { - getStream(stream, Object.assign({}, opts, { encoding: "buffer" })); + void getStream(stream, Object.assign({}, opts, { encoding: "buffer" })); } +// FIXME: should these be async ? export function array(stream: Readable, opts: Options = {}) { - getStream(stream, Object.assign({}, opts, { array: true })); + void getStream(stream, Object.assign({}, opts, { array: true })); } diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index 88e78f414..ba6891857 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -1,3 +1,6 @@ +// FIXME: NEEDS REFACTOR +/* eslint-disable @typescript-eslint/no-shadow */ +/* eslint-disable @typescript-eslint/naming-convention */ /** * CJSON.ts * This file is used to generate cJSON code with quicktype @@ -784,6 +787,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param unionType: union type */ protected emitUnionTypedef(unionType: UnionType): void { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_hasNull, nonNulls] = removeNullFromUnion(unionType); const unionName = this.nameForNamedType(unionType); diff --git a/packages/quicktype-core/src/language/Dart.ts b/packages/quicktype-core/src/language/Dart.ts index 59476c982..42b6f3e70 100644 --- a/packages/quicktype-core/src/language/Dart.ts +++ b/packages/quicktype-core/src/language/Dart.ts @@ -461,9 +461,11 @@ export class DartRenderer extends ConvenienceRenderer { return [this.nameForNamedType(classType), ".", this.fromJson, "(", dynamic, ")"]; } + // FIXME: refactor this // If the first time is the unionType type, after nullableFromUnion conversion, // the isNullable property will become false, which is obviously wrong, // so add isNullable property + // eslint-disable-next-line @typescript-eslint/default-param-last protected fromDynamicExpression(isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, @@ -524,9 +526,11 @@ export class DartRenderer extends ConvenienceRenderer { ); } + // FIXME: refactor this // If the first time is the unionType type, after nullableFromUnion conversion, // the isNullable property will become false, which is obviously wrong, // so add isNullable property + // eslint-disable-next-line @typescript-eslint/default-param-last protected toDynamicExpression(isNullable: boolean = false, t: Type, ...dynamic: Sourcelike[]): Sourcelike { return matchType( t, diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts index a2ae5b40c..8bd7c0e05 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts @@ -17,7 +17,7 @@ import { utf16StringEscape } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type, ArrayType } from "../Type"; +import { type ArrayType, type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type } from "../Type"; import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; import { directlyReachableSingleNamedType, matchType } from "../TypeUtils"; @@ -244,18 +244,18 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { const names = source.filter(value => value as Name); // must be behind all these names - for (let i = 0; i < names.length; i++) { - const depName = names[i]; + names.forEach(name => { + const depName = name; // find this name's ordinal, if it has already been added - for (let j = 0; j < order.length; j++) { - const depIndex = order[j]; + order.forEach(orderItem => { + const depIndex = orderItem; if (mapKey[depIndex] === depName) { // this is the index of the dependency, so make sure we come after it ordinal = Math.max(ordinal, depIndex + 1); } - } - } + }); + }); // insert index order.splice(ordinal, 0, index); diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts index 06de856a7..01bf4cd9d 100644 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ b/packages/quicktype-core/src/language/Kotlin.ts @@ -181,6 +181,7 @@ function unicodeEscape(codePoint: number): string { return "\\u" + intToHex(codePoint, 4); } +// eslint-disable-next-line @typescript-eslint/naming-convention const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); function stringEscape(s: string): string { diff --git a/packages/quicktype-core/src/language/Php.ts b/packages/quicktype-core/src/language/Php.ts index f3b07ef2f..617f461fe 100644 --- a/packages/quicktype-core/src/language/Php.ts +++ b/packages/quicktype-core/src/language/Php.ts @@ -367,7 +367,7 @@ export class PhpRenderer extends ConvenienceRenderer { } protected phpToObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { - matchType( + matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), _nullType => this.emitLine(...lhs, ...args, "; /*null*/"), @@ -429,7 +429,7 @@ export class PhpRenderer extends ConvenienceRenderer { } protected phpFromObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { - matchType( + matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), _nullType => this.emitLine(...lhs, ...args, "; /*null*/"), @@ -492,7 +492,7 @@ export class PhpRenderer extends ConvenienceRenderer { idx: number, suffix: Sourcelike ) { - matchType( + matchType( t, _anyType => this.emitLine( @@ -593,7 +593,7 @@ export class PhpRenderer extends ConvenienceRenderer { ); }; - matchType( + matchType( t, _anyType => is("defined"), _nullType => is("is_null"), diff --git a/packages/quicktype-core/src/language/Python.ts b/packages/quicktype-core/src/language/Python.ts index 1066fcd11..37e5106b4 100644 --- a/packages/quicktype-core/src/language/Python.ts +++ b/packages/quicktype-core/src/language/Python.ts @@ -581,6 +581,8 @@ export interface ValueOrLambda { // * If `input` is a value, the result is `f(input)`. // * If `input` is a lambda, the result is `lambda x: f(input(x))` function compose(input: ValueOrLambda, f: (arg: Sourcelike) => Sourcelike): ValueOrLambda; +// FIXME: refactor this +// eslint-disable-next-line @typescript-eslint/unified-signatures function compose(input: ValueOrLambda, f: ValueOrLambda): ValueOrLambda; function compose(input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => Sourcelike)): ValueOrLambda { if (typeof f === "function") { diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust.ts index 2ffa07689..ca36ca6d8 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { mapFirst } from "collection-utils"; import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; @@ -414,7 +415,10 @@ export class RustRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, blankLines, (name, jsonName, prop) => { this.emitDescription(this.descriptionForClassProperty(c, jsonName)); this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle); - this._options.skipSerializingNone && this.emitSkipSerializeNone(prop.type); + if (this._options.skipSerializingNone) { + this.emitSkipSerializeNone(prop.type); + } + this.emitLine(this.visibility, name, ": ", this.breakCycle(prop.type, true), ","); }); diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts index 38a7cd451..69dc3c9fd 100644 --- a/packages/quicktype-core/src/language/Scala3.ts +++ b/packages/quicktype-core/src/language/Scala3.ts @@ -558,7 +558,7 @@ export class Smithy4sRenderer extends Scala3Renderer { export class CirceRenderer extends Scala3Renderer { private seenUnionTypes: string[] = []; - protected circeEncoderForType(t: Type, _ = false, noOptional = false, paramName: string = ""): Sourcelike { + protected circeEncoderForType(t: Type, __ = false, noOptional = false, paramName: string = ""): Sourcelike { return matchType( t, _anyType => ["Encoder.encodeJson(", paramName, ")"], diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts index d288fea9a..470a79efb 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts @@ -181,7 +181,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { } } - protected walkObjectNames(type: ObjectType) { + protected walkObjectNames(objectType: ObjectType) { const names: Name[] = []; const recurse = (type: Type) => { @@ -201,7 +201,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { } }; - this.forEachClassProperty(type, "none", (_, __, prop) => { + this.forEachClassProperty(objectType, "none", (_, __, prop) => { recurse(prop.type); }); @@ -232,18 +232,18 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { const names = this.walkObjectNames(source); // must be behind all these names - for (let i = 0; i < names.length; i++) { - const depName = names[i]; + names.forEach(name => { + const depName = name; // find this name's ordinal, if it has already been added - for (let j = 0; j < order.length; j++) { - const depIndex = order[j]; + order.forEach(orderItem => { + const depIndex = orderItem; if (mapKey[depIndex] === depName) { // this is the index of the dependency, so make sure we come after it ordinal = Math.max(ordinal, depIndex + 1); } - } - } + }); + }); // insert index order.splice(ordinal, 0, index); diff --git a/packages/quicktype-core/src/language/TypeScriptZod.ts b/packages/quicktype-core/src/language/TypeScriptZod.ts index 57a67d1d2..69cd77fda 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod.ts @@ -300,6 +300,9 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { let found = false; // find this childs's ordinal, if it has already been added // faster to go through what we've defined so far than all definitions + + // FIXME: refactor this + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let j = 0; j < order.length; j++) { const childIndex = order[j]; if (mapTypeRef[childIndex] === childRef) { diff --git a/packages/quicktype-core/src/rewrites/ExpandStrings.ts b/packages/quicktype-core/src/rewrites/ExpandStrings.ts index c1ee3331e..abddcfab5 100644 --- a/packages/quicktype-core/src/rewrites/ExpandStrings.ts +++ b/packages/quicktype-core/src/rewrites/ExpandStrings.ts @@ -68,7 +68,7 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum const keys = Array.from(cases.keys()); if (isAlwaysEmptyString(keys)) return undefined; - const someCaseIsNotNumber = iterableSome(keys, key => /^(\-|\+)?[0-9]+(\.[0-9]+)?$/.test(key) === false); + const someCaseIsNotNumber = iterableSome(keys, key => /^[-+]?[0-9]+(\.[0-9]+)?$/.test(key) === false); if (!someCaseIsNotNumber) return undefined; } @@ -85,6 +85,8 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum enumInfos.set(t, enumInfo); } + // FIXME: refactor this + // eslint-disable-next-line no-inner-declarations function findOverlap(newCases: ReadonlySet, newAreSubordinate: boolean): number { return enumSets.findIndex(s => enumCasesOverlap(newCases, s, newAreSubordinate)); } diff --git a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts index ffe2f8a64..a992ead9f 100644 --- a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts +++ b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/brace-style */ import { iterableEvery, iterableFind, @@ -186,7 +187,7 @@ class IntersectionAccumulator public addType(t: Type): TypeAttributes { let attributes = t.getAttributes(); - matchTypeExhaustive( + matchTypeExhaustive( t, _noneType => { return panic("There shouldn't be a none type"); diff --git a/packages/quicktype-core/src/support/Strings.ts b/packages/quicktype-core/src/support/Strings.ts index 1ea40e3d6..bd76ee4f9 100644 --- a/packages/quicktype-core/src/support/Strings.ts +++ b/packages/quicktype-core/src/support/Strings.ts @@ -52,6 +52,7 @@ function precomputedCodePointPredicate(p: CodePointPredicate): CodePointPredicat export function utf16ConcatMap(mapper: (utf16Unit: number) => string): (s: string) => string { const { charStringMap, charNoEscapeMap } = computeAsciiMap(mapper); + // eslint-disable-next-line @typescript-eslint/naming-convention return function stringConcatMap_inner(s: string): string { let cs: string[] | null = null; let start = 0; @@ -94,6 +95,7 @@ function isLowSurrogate(cc: number): boolean { export function utf32ConcatMap(mapper: (codePoint: number) => string): (s: string) => string { const { charStringMap, charNoEscapeMap } = computeAsciiMap(mapper); + // eslint-disable-next-line @typescript-eslint/naming-convention return function stringConcatMap_inner(s: string): string { let cs: string[] | null = null; let start = 0; diff --git a/src/CompressedJSONFromStream.ts b/src/CompressedJSONFromStream.ts index 7d7be8830..16a9c78b0 100644 --- a/src/CompressedJSONFromStream.ts +++ b/src/CompressedJSONFromStream.ts @@ -48,7 +48,7 @@ export class CompressedJSONFromStream extends CompressedJSON { protected handleNumberChunk = (s: string): void => { const ctx = this.context; - if (!ctx.currentNumberIsDouble && /[\.e]/i.test(s)) { + if (!ctx.currentNumberIsDouble && /[.e]/i.test(s)) { ctx.currentNumberIsDouble = true; } }; From c0232f36e45ac222f32c50d0ea80c80518b18621 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 20:26:39 -0700 Subject: [PATCH 25/80] downgrade remaining to warnings --- .eslintignore | 2 ++ .eslintrc.json | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.eslintignore b/.eslintignore index 0fd88d904..135b09976 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,5 @@ packages/*/dist packages/*/node_modules test/runs test/input + +license diff --git a/.eslintrc.json b/.eslintrc.json index a5cf75933..f35b5c03c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -27,6 +27,8 @@ "rules": { "comma-dangle": "off", "no-extra-parens": "off", + "no-case-declarations": "warn", + "no-duplicate-imports": "error", "canonical/prefer-inline-type-import": "error", "typescript-sort-keys/string-enum": "off", @@ -36,7 +38,6 @@ "ignoreDeclarationSort": true } ], - "no-duplicate-imports": "error", "import/first": "error", "import/order": [ "error", @@ -72,10 +73,10 @@ "@typescript-eslint/indent": "off", "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true }], "@typescript-eslint/member-delimiter-style": "off", - "@typescript-eslint/naming-convention": "error", "@typescript-eslint/no-base-to-string": "warn", "@typescript-eslint/no-empty-interface": "warn", "@typescript-eslint/no-extra-parens": "off", + "@typescript-eslint/no-loop-func": "warn", "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], "@typescript-eslint/no-unused-vars": ["error", { "vars": "local", "args": "none" }], "@typescript-eslint/no-use-before-define": "warn", @@ -85,6 +86,7 @@ "@typescript-eslint/require-array-sort-compare": "off", "@typescript-eslint/space-before-function-paren": "off", "@typescript-eslint/switch-exhaustiveness-check": "error", + "@typescript-eslint/unbound-method": "warn", "@typescript-eslint/unified-signatures": "error" }, "overrides": [ From 59e877fab6e8bdf0f008adb240a89b4b1645a382 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 20:55:42 -0700 Subject: [PATCH 26/80] return types --- .../quicktype-core/src/ConvenienceRenderer.ts | 10 ++-- packages/quicktype-core/src/GatherNames.ts | 4 +- .../quicktype-core/src/MakeTransformations.ts | 4 +- packages/quicktype-core/src/MarkovChain.ts | 2 +- packages/quicktype-core/src/Naming.ts | 2 +- packages/quicktype-core/src/Transformers.ts | 8 +-- packages/quicktype-core/src/Type.ts | 7 ++- packages/quicktype-core/src/TypeUtils.ts | 2 +- .../src/attributes/EnumValues.ts | 2 +- .../src/input/JSONSchemaInput.ts | 16 +++--- packages/quicktype-core/src/language/CJSON.ts | 10 ++-- .../quicktype-core/src/language/CPlusPlus.ts | 8 +-- .../quicktype-core/src/language/Crystal.ts | 2 +- packages/quicktype-core/src/language/Dart.ts | 2 +- packages/quicktype-core/src/language/Java.ts | 14 ++--- .../quicktype-core/src/language/JavaScript.ts | 10 ++-- .../src/language/JavaScriptPropTypes.ts | 6 +-- .../quicktype-core/src/language/Kotlin.ts | 26 ++++----- .../src/language/Objective-C.ts | 20 +++---- packages/quicktype-core/src/language/Php.ts | 54 +++++++++++++------ packages/quicktype-core/src/language/Pike.ts | 12 ++--- .../quicktype-core/src/language/Python.ts | 5 +- packages/quicktype-core/src/language/Rust.ts | 6 +-- .../quicktype-core/src/language/Scala3.ts | 8 +-- .../quicktype-core/src/language/Smithy4s.ts | 4 +- packages/quicktype-core/src/language/Swift.ts | 12 ++--- .../src/language/TypeScriptEffectSchema.ts | 8 +-- .../src/language/TypeScriptFlow.ts | 6 +-- .../src/language/TypeScriptZod.ts | 4 +- .../quicktype-core/src/language/ruby/index.ts | 20 +++---- .../quicktype-core/src/support/Acronyms.ts | 2 +- .../quicktype-core/src/support/Converters.ts | 2 +- src/index.ts | 6 +-- 33 files changed, 166 insertions(+), 138 deletions(-) diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index df5e02578..2c9c6ff42 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -681,7 +681,7 @@ export abstract class ConvenienceRenderer extends Renderer { protected forEachDeclaration( blankLocations: BlankLineConfig, f: (decl: Declaration, position: ForEachPosition) => void - ) { + ): void { this.forEachWithBlankLines( iterableEnumerate(defined(this._declarationIR).declarations), blankLocations, @@ -748,7 +748,7 @@ export abstract class ConvenienceRenderer extends Renderer { ): void { const iterateMembers = members ?? u.members; if (sortOrder === null) { - sortOrder = n => defined(this.names.get(n)); + sortOrder = (n): string => defined(this.names.get(n)); } const memberNames = mapFilter(defined(this._memberNamesStoreView).get(u), (_, t) => iterateMembers.has(t)); @@ -922,7 +922,7 @@ export abstract class ConvenienceRenderer extends Renderer { makePropertyRow: (name: Name, jsonName: string, p: ClassProperty) => Sourcelike[] ): void { let table: Sourcelike[][] = []; - const emitTable = () => { + const emitTable = (): void => { if (table.length === 0) return; this.emitTable(table); table = []; @@ -943,7 +943,7 @@ export abstract class ConvenienceRenderer extends Renderer { private processGraph(): void { this._declarationIR = declarationsForGraph( this.typeGraph, - this.needsTypeDeclarationBeforeUse ? t => this.canBeForwardDeclared(t) : undefined, + this.needsTypeDeclarationBeforeUse ? (t): boolean => this.canBeForwardDeclared(t) : undefined, t => this.childrenOfType(t), t => { if (t instanceof UnionType) { @@ -976,7 +976,7 @@ export abstract class ConvenienceRenderer extends Renderer { const processed = new Set(); const queue = Array.from(this.typeGraph.topLevels.values()); - function visit(t: Type) { + function visit(t: Type): void { if (visitedTypes.has(t)) return; for (const c of t.getChildren()) { queue.push(c); diff --git a/packages/quicktype-core/src/GatherNames.ts b/packages/quicktype-core/src/GatherNames.ts index 2dba2afb3..4d8142d07 100644 --- a/packages/quicktype-core/src/GatherNames.ts +++ b/packages/quicktype-core/src/GatherNames.ts @@ -102,7 +102,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: // null means there are too many const namesForType = new Map | null>(); - function addNames(t: Type, names: ReadonlySet | null) { + function addNames(t: Type, names: ReadonlySet | null): void { // Always use the type's given names if it has some if (t.hasNames) { const originalNames = t.getNames(); @@ -217,7 +217,7 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: return null; } - function processType(ancestor: Type | undefined, t: Type, alternativeSuffix: string | undefined) { + function processType(ancestor: Type | undefined, t: Type, alternativeSuffix: string | undefined): void { const names = defined(namesForType.get(t)); let processedEntry = pairsProcessed.get(ancestor); diff --git a/packages/quicktype-core/src/MakeTransformations.ts b/packages/quicktype-core/src/MakeTransformations.ts index fc3bf23f5..106eebbd5 100644 --- a/packages/quicktype-core/src/MakeTransformations.ts +++ b/packages/quicktype-core/src/MakeTransformations.ts @@ -118,7 +118,7 @@ function replaceUnion( ? builder.getUnionType(union.getAttributes(), reconstitutedMemberSet) : defined(iterableFirst(reconstitutedMemberSet)); - function memberForKind(kind: TypeKind) { + function memberForKind(kind: TypeKind): number { return defined(reconstitutedMembersByKind.get(kind)); } @@ -127,7 +127,7 @@ function replaceUnion( return new UnionInstantiationTransformer(graph, memberTypeRef); } - function transformerForKind(kind: TypeKind) { + function transformerForKind(kind: TypeKind): DecodingTransformer | undefined { const member = union.findMember(kind); if (member === undefined) return undefined; const memberTypeRef = memberForKind(kind); diff --git a/packages/quicktype-core/src/MarkovChain.ts b/packages/quicktype-core/src/MarkovChain.ts index 9a3fa5f84..dec67dc1f 100644 --- a/packages/quicktype-core/src/MarkovChain.ts +++ b/packages/quicktype-core/src/MarkovChain.ts @@ -123,7 +123,7 @@ export function evaluate(mc: MarkovChain, word: string): number { return evaluateFull(mc, word)[0]; } -function randomInt(lower: number, upper: number) { +function randomInt(lower: number, upper: number): number { const range = upper - lower; return lower + Math.floor(Math.random() * range); } diff --git a/packages/quicktype-core/src/Naming.ts b/packages/quicktype-core/src/Naming.ts index d23dd30fc..94c6ca452 100644 --- a/packages/quicktype-core/src/Naming.ts +++ b/packages/quicktype-core/src/Naming.ts @@ -319,7 +319,7 @@ export class DependencyName extends Name { } } -export function keywordNamespace(name: string, keywords: string[]) { +export function keywordNamespace(name: string, keywords: string[]): Namespace { const ns = new Namespace(name, undefined, [], []); for (const kw of keywords) { ns.add(new FixedName(kw)); diff --git a/packages/quicktype-core/src/Transformers.ts b/packages/quicktype-core/src/Transformers.ts index b1b93bfa3..d6bbb49f7 100644 --- a/packages/quicktype-core/src/Transformers.ts +++ b/packages/quicktype-core/src/Transformers.ts @@ -449,7 +449,7 @@ export class DecodingChoiceTransformer extends Transformer { public get transformers(): readonly Transformer[] { const transformers: Transformer[] = []; - function add(xfer: Transformer | undefined) { + function add(xfer: Transformer | undefined): void { if (xfer === undefined) return; transformers.push(xfer); } @@ -496,7 +496,7 @@ export class DecodingChoiceTransformer extends Transformer { let transformers = new Map(); let memberMatchTransformers = new Map(); - function addCase(reversed: Transformer) { + function addCase(reversed: Transformer): void { if (reversed instanceof UnionMemberMatchTransformer) { const memberType = reversed.memberType; let arr = memberMatchTransformers.get(memberType); @@ -518,7 +518,7 @@ export class DecodingChoiceTransformer extends Transformer { } } - function reverseAndAdd(transformer: Transformer) { + function reverseAndAdd(transformer: Transformer): void { const reversed = transformer.reverse(targetTypeRef, undefined); let cases: readonly Transformer[] = []; // Flatten nested ChoiceTransformers @@ -578,7 +578,7 @@ export class DecodingChoiceTransformer extends Transformer { } public reconstitute(builder: TBuilder): Transformer { - function reconstitute(xf: Transformer | undefined) { + function reconstitute(xf: Transformer | undefined): Transformer | undefined { if (xf === undefined) return undefined; return xf.reconstitute(builder); } diff --git a/packages/quicktype-core/src/Type.ts b/packages/quicktype-core/src/Type.ts index d5bab5cf2..cdbae768e 100644 --- a/packages/quicktype-core/src/Type.ts +++ b/packages/quicktype-core/src/Type.ts @@ -373,7 +373,7 @@ export class ArrayType extends Type { super(typeRef, graph); } - public setItems(itemsRef: TypeRef) { + public setItems(itemsRef: TypeRef): void { if (this._itemsRef !== undefined) { return panic("Can only set array items once"); } @@ -514,7 +514,10 @@ export class ObjectType extends Type { } } - public setProperties(properties: ReadonlyMap, additionalPropertiesRef: TypeRef | undefined) { + public setProperties( + properties: ReadonlyMap, + additionalPropertiesRef: TypeRef | undefined + ): void { assert(this._properties === undefined, "Tried to set object properties twice"); if (this instanceof MapType) { diff --git a/packages/quicktype-core/src/TypeUtils.ts b/packages/quicktype-core/src/TypeUtils.ts index f0136fc32..b2ae456f7 100644 --- a/packages/quicktype-core/src/TypeUtils.ts +++ b/packages/quicktype-core/src/TypeUtils.ts @@ -296,7 +296,7 @@ export function matchType( unionType: (unionType: UnionType) => U, transformedStringType?: (transformedStringType: PrimitiveType) => U ): U { - function typeNotSupported(t: Type) { + function typeNotSupported(t: Type): never { return panic(`Unsupported type ${t.kind} in non-exhaustive match`); } diff --git a/packages/quicktype-core/src/attributes/EnumValues.ts b/packages/quicktype-core/src/attributes/EnumValues.ts index 1f66958e3..05885ada9 100644 --- a/packages/quicktype-core/src/attributes/EnumValues.ts +++ b/packages/quicktype-core/src/attributes/EnumValues.ts @@ -12,7 +12,7 @@ class EnumValuesTypeAttributeKind extends TypeAttributeKind { super("enumValues"); } - public makeInferred(_: AccessorNames) { + public makeInferred(_: AccessorNames): undefined { return undefined; } } diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index 244e682be..a88e78157 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -296,7 +296,7 @@ export class Ref { } private lookup(local: unknown, path: readonly PathElement[], root: JSONSchema): JSONSchema { - const refMaker = () => new Ref(this.addressURI, path); + const refMaker = (): Ref => new Ref(this.addressURI, path); const first = path[0]; if (first === undefined) { return checkJSONSchema(local, refMaker); @@ -391,7 +391,7 @@ class Location { this.virtualRef = virtualRef ?? canonicalRef; } - public updateWithID(id: string | unknown) { + public updateWithID(id: string | unknown): Location { if (typeof id !== "string") return this; const parsed = Ref.parse(id); const virtual = this.haveID ? parsed.resolveAgainst(this.virtualRef) : parsed; @@ -426,7 +426,7 @@ class Canonizer { public constructor(private readonly _ctx: RunContext) {} - private addIDs(schema: unknown, loc: Location) { + private addIDs(schema: unknown, loc: Location): void { if (schema === null) return; if (Array.isArray(schema)) { for (let i = 0; i < schema.length; i++) { @@ -681,7 +681,7 @@ async function addTypesInSchema( properties: StringMap, requiredArray: string[], additionalProperties: unknown, - sortKey: (k: string) => number | string = (k: string) => k.toLowerCase() + sortKey: (k: string) => number | string = (k: string): string => k.toLowerCase() ): Promise { const required = new Set(requiredArray); const propertiesMap = mapSortBy(mapFromObject(properties), (_, k) => sortKey(k)); @@ -739,13 +739,13 @@ async function addTypesInSchema( let predicate: (x: unknown) => boolean; switch (name) { case "null": - predicate = (x: unknown) => x === null; + predicate = (x): x is null => x === null; break; case "integer": - predicate = (x: unknown) => typeof x === "number" && x === Math.floor(x); + predicate = (x): x is number => typeof x === "number" && x === Math.floor(x); break; default: - predicate = (x: unknown) => typeof x === name; + predicate = (x): x is typeof name => typeof x === name; break; } @@ -908,7 +908,7 @@ async function addTypesInSchema( combineProducedAttributes(({ forObject }) => forObject) ); const order = schema.quicktypePropertyOrder ? schema.quicktypePropertyOrder : []; - const orderKey = (propertyName: string) => { + const orderKey = (propertyName: string): string => { // use the index of the order array const index = order.indexOf(propertyName); // if no index then use the property name diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index ba6891857..3cfe6b976 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -498,7 +498,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param fieldType: the variable type * @param fieldName: name of the variable */ - protected emitTypdefAlias(fieldType: Type, fieldName: Name) { + protected emitTypedefAlias(fieldType: Type, fieldName: Name) { if (this._options.addTypedefAlias) { this.emitLine("typedef ", this.quicktypeTypeToCJSON(fieldType, false).cType, " ", fieldName, ";"); this.ensureBlankLine(); @@ -686,7 +686,7 @@ export class CJSONRenderer extends ConvenienceRenderer { true ); this.ensureBlankLine(); - this.emitTypdefAlias(enumType, enumName); + this.emitTypedefAlias(enumType, enumName); } /** @@ -819,7 +819,7 @@ export class CJSONRenderer extends ConvenienceRenderer { true ); this.ensureBlankLine(); - this.emitTypdefAlias(unionType, unionName); + this.emitTypedefAlias(unionType, unionName); } /** @@ -1697,7 +1697,7 @@ export class CJSONRenderer extends ConvenienceRenderer { true ); this.ensureBlankLine(); - this.emitTypdefAlias(classType, className); + this.emitTypedefAlias(classType, className); } /** @@ -3295,7 +3295,7 @@ export class CJSONRenderer extends ConvenienceRenderer { true ); this.ensureBlankLine(); - this.emitTypdefAlias(type, className); + this.emitTypedefAlias(type, className); } /** diff --git a/packages/quicktype-core/src/language/CPlusPlus.ts b/packages/quicktype-core/src/language/CPlusPlus.ts index c787a8778..910f714f9 100644 --- a/packages/quicktype-core/src/language/CPlusPlus.ts +++ b/packages/quicktype-core/src/language/CPlusPlus.ts @@ -1136,7 +1136,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { */ protected generatedTypes(isClassMember: boolean, theType: Type): TypeRecord[] { const result: TypeRecord[] = []; - const recur = (forceInclude: boolean, isVariant: boolean, l: number, t: Type) => { + const recur = (forceInclude: boolean, isVariant: boolean, l: number, t: Type): void => { if (t instanceof ArrayType) { recur(true, isVariant, l + 1, t.items); } else if (t instanceof ClassType) { @@ -1953,7 +1953,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("void to_json(json & j, ", this.withConst([ourQualifier, enumName]), " & x);"); } - private isLargeEnum(e: EnumType) { + private isLargeEnum(e: EnumType): boolean { // This is just an estimation. Someone might want to do some // benchmarks to find the optimum value here return e.cases.size > 15; @@ -2125,7 +2125,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine("#define NLOHMANN_OPT_HELPER"); this.emitNamespaces(["nlohmann"], () => { - const emitAdlStruct = (optType: string, factory: string) => { + const emitAdlStruct = (optType: string, factory: string): void => { this.emitLine("template "); this.emitBlock(["struct adl_serializer<", optType, ">"], true, () => { this.emitBlock( @@ -2995,7 +2995,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - protected isConversionRequired(t: Type) { + protected isConversionRequired(t: Type): boolean { const originalType = this.cppType( t, { diff --git a/packages/quicktype-core/src/language/Crystal.ts b/packages/quicktype-core/src/language/Crystal.ts index 3b06122af..9816191bc 100644 --- a/packages/quicktype-core/src/language/Crystal.ts +++ b/packages/quicktype-core/src/language/Crystal.ts @@ -322,7 +322,7 @@ export class CrystalRenderer extends ConvenienceRenderer { protected emitStructDefinition(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); - const structBody = () => + const structBody = (): void => this.forEachClassProperty(c, "none", (name, jsonName, prop) => { this.ensureBlankLine(); this.emitDescription(this.descriptionForClassProperty(c, jsonName)); diff --git a/packages/quicktype-core/src/language/Dart.ts b/packages/quicktype-core/src/language/Dart.ts index 42b6f3e70..d8d471ec9 100644 --- a/packages/quicktype-core/src/language/Dart.ts +++ b/packages/quicktype-core/src/language/Dart.ts @@ -444,7 +444,7 @@ export class DartRenderer extends ConvenienceRenderer { return ["Map.from(", map, ").map((k, v) => MapEntry(k, ", valueMapper, "))"]; } - protected mapClass(isNullable: boolean, classType: ClassType, dynamic: Sourcelike) { + protected mapClass(isNullable: boolean, classType: ClassType, dynamic: Sourcelike): Sourcelike { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return [ dynamic, diff --git a/packages/quicktype-core/src/language/Java.ts b/packages/quicktype-core/src/language/Java.ts index 6954a13f4..d800e9fbf 100644 --- a/packages/quicktype-core/src/language/Java.ts +++ b/packages/quicktype-core/src/language/Java.ts @@ -664,7 +664,7 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitLine("}"); } - public emitTryCatch(main: () => void, handler: () => void, exception = "Exception") { + public emitTryCatch(main: () => void, handler: () => void, exception = "Exception"): void { this.emitLine("try {"); this.indent(main); this.emitLine("} catch (", exception, " ex) {"); @@ -672,7 +672,7 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitLine("}"); } - public emitIgnoredTryCatchBlock(f: () => void) { + public emitIgnoredTryCatchBlock(f: () => void): void { this.emitTryCatch(f, () => this.emitLine("// Ignored")); } @@ -913,11 +913,11 @@ export class JavaRenderer extends ConvenienceRenderer { this.finishFile(); } - protected emitEnumSerializationAttributes(_e: EnumType) { + protected emitEnumSerializationAttributes(_e: EnumType): void { // Empty } - protected emitEnumDeserializationAttributes(_e: EnumType) { + protected emitEnumDeserializationAttributes(_e: EnumType): void { // Empty } @@ -1158,7 +1158,7 @@ export class JacksonRenderer extends JavaRenderer { }); }; - const emitStringDeserializer = () => { + const emitStringDeserializer = (): void => { const enumType = u.findMember("enum"); const stringType = u.findMember("string"); @@ -1307,11 +1307,11 @@ export class JacksonRenderer extends JavaRenderer { }); } - protected emitEnumSerializationAttributes(_e: EnumType) { + protected emitEnumSerializationAttributes(_e: EnumType): void { this.emitLine("@JsonValue"); } - protected emitEnumDeserializationAttributes(_e: EnumType) { + protected emitEnumDeserializationAttributes(_e: EnumType): void { this.emitLine("@JsonCreator"); } diff --git a/packages/quicktype-core/src/language/JavaScript.ts b/packages/quicktype-core/src/language/JavaScript.ts index ff435edc1..440502cff 100644 --- a/packages/quicktype-core/src/language/JavaScript.ts +++ b/packages/quicktype-core/src/language/JavaScript.ts @@ -122,7 +122,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { legalizeName, upper ? firstUpperWordStyle : allLowerWordStyle, firstUpperWordStyle, - upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, + upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", isES3IdentifierStart @@ -204,13 +204,13 @@ export class JavaScriptRenderer extends ConvenienceRenderer { return ["u(undefined, ", typeMap, ")"]; } - protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void) { + protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void): void { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); } - private emitTypeMap() { + private emitTypeMap(): void { const { any: anyAnnotation } = this.typeAnnotations; this.emitBlock(`const typeMap${anyAnnotation} = `, ";", () => { @@ -284,7 +284,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { } protected emitConvertModuleBody(): void { - const converter = (t: Type, name: Name) => { + const converter = (t: Type, name: Name): void => { const typeMap = this.typeMapTypeFor(t); this.emitBlock([this.deserializerFunctionLine(t, name), " "], "", () => { const parsedJson = this._jsOptions.rawType === "json" ? "JSON.parse(json)" : "json"; @@ -553,7 +553,7 @@ function r(name${stringAnnotation}) { }); } - protected emitSourceStructure() { + protected emitSourceStructure(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else { diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts index 8bd7c0e05..6754e83e2 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes.ts @@ -82,7 +82,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { legalizeName, upper ? firstUpperWordStyle : allLowerWordStyle, firstUpperWordStyle, - upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, + upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", isES3IdentifierStart @@ -187,7 +187,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { ); } - protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void) { + protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void): void { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); @@ -281,7 +281,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { }); } - private emitObject(name: Name, t: ObjectType) { + private emitObject(name: Name, t: ObjectType): void { this.ensureBlankLine(); this.emitLine("_", name, " = PropTypes.shape({"); this.indent(() => { diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts index 01bf4cd9d..9ef6d5937 100644 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ b/packages/quicktype-core/src/language/Kotlin.ts @@ -323,7 +323,7 @@ export class KotlinRenderer extends ConvenienceRenderer { return; } - const kotlinType = (p: ClassProperty) => { + const kotlinType = (p: ClassProperty): Sourcelike => { if (p.isOptional) { return [this.kotlinType(p.type, true, true), "?"]; } else { @@ -371,15 +371,15 @@ export class KotlinRenderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(c, className); } - protected emitClassDefinitionMethods(_c: ClassType, _className: Name) { + protected emitClassDefinitionMethods(_c: ClassType, _className: Name): void { this.emitLine(")"); } - protected emitClassAnnotations(_c: Type, _className: Name) { + protected emitClassAnnotations(_c: Type, _className: Name): void { // to be overridden } - protected renameAttribute(_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>) { + protected renameAttribute(_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>): void { // to be overridden } @@ -433,7 +433,7 @@ export class KotlinRenderer extends ConvenienceRenderer { _nonNulls: ReadonlySet, _maybeNull: PrimitiveType | null, _unionName: Name - ) { + ): void { // to be overridden } @@ -630,7 +630,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { this.emitLine("typealias ", className, " = JsonObject"); } - protected emitClassDefinitionMethods(c: ClassType, className: Name) { + protected emitClassDefinitionMethods(c: ClassType, className: Name): void { const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); if (isTopLevel) { this.emitBlock(")", () => { @@ -645,7 +645,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } } - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { + protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): void { const rename = this.klaxonRenameAttribute(name, jsonName); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); @@ -701,7 +701,7 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, unionName: Name - ) { + ): void { this.ensureBlankLine(); this.emitLine("public fun toJson(): String = klaxon.toJsonString(when (this) {"); this.indent(() => { @@ -911,7 +911,7 @@ import com.fasterxml.jackson.module.kotlin.*`); this.emitLine("typealias ", className, " = JsonNode"); } - protected emitClassDefinitionMethods(c: ClassType, className: Name) { + protected emitClassDefinitionMethods(c: ClassType, className: Name): void { const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); if (isTopLevel) { this.emitBlock(")", () => { @@ -926,7 +926,7 @@ import com.fasterxml.jackson.module.kotlin.*`); } } - protected renameAttribute(name: Name, jsonName: string, required: boolean, meta: Array<() => void>) { + protected renameAttribute(name: Name, jsonName: string, required: boolean, meta: Array<() => void>): void { const rename = this.jacksonRenameAttribute(name, jsonName, required); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); @@ -974,7 +974,7 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, unionName: Name - ) { + ): void { this.ensureBlankLine(); this.emitLine("fun toJson(): String = mapper.writeValueAsString(when (this) {"); this.indent(() => { @@ -1086,11 +1086,11 @@ export class KotlinXRenderer extends KotlinRenderer { this.emitLine("import kotlinx.serialization.encoding.*"); } - protected emitClassAnnotations(_c: Type, _className: Name) { + protected emitClassAnnotations(_c: Type, _className: Name): void { this.emitLine("@Serializable"); } - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>) { + protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): void { const rename = this._rename(name, jsonName); if (rename !== undefined) { meta.push(() => this.emitLine(rename)); diff --git a/packages/quicktype-core/src/language/Objective-C.ts b/packages/quicktype-core/src/language/Objective-C.ts index 00d678f30..3b46b914b 100644 --- a/packages/quicktype-core/src/language/Objective-C.ts +++ b/packages/quicktype-core/src/language/Objective-C.ts @@ -308,14 +308,14 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("}"); } - protected emitMethod(declaration: Sourcelike, f: () => void) { + protected emitMethod(declaration: Sourcelike, f: () => void): void { this.emitLine(declaration); this.emitLine("{"); this.indent(f); this.emitLine("}"); } - protected emitExtraComments(...comments: Sourcelike[]) { + protected emitExtraComments(...comments: Sourcelike[]): void { if (!this._options.extraComments) return; for (const comment of comments) { this.emitLine("// ", comment); @@ -496,7 +496,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return this.implicitlyConvertsFromJSON(t) && "bool" !== t.kind; } - protected emitPropertyAssignment(propertyName: Name, jsonName: string, propertyType: Type) { + protected emitPropertyAssignment(propertyName: Name, jsonName: string, propertyType: Type): void { const name = ["_", propertyName]; matchType( propertyType, @@ -587,7 +587,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine(this.topLevelToJSONPrototype(name, true), ";"); } - private emitTryCatchAsError(inTry: () => void, inCatch: () => void) { + private emitTryCatchAsError(inTry: () => void, inCatch: () => void): void { this.emitLine("@try {"); this.indent(inTry); this.emitLine("} @catch (NSException *exception) {"); @@ -680,7 +680,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - protected hasIrregularProperties(t: ClassType) { + protected hasIrregularProperties(t: ClassType): boolean { let irregular = false; this.forEachClassProperty(t, "none", (name, jsonName) => { irregular = irregular || stringEscape(jsonName) !== this.sourcelikeToString(name); @@ -688,7 +688,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return irregular; } - protected hasUnsafeProperties(t: ClassType) { + protected hasUnsafeProperties(t: ClassType): boolean { let unsafe = false; this.forEachClassProperty(t, "none", (_, __, property) => { unsafe = unsafe || !this.implicitlyConvertsToJSON(property.type); @@ -830,7 +830,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - protected emitMark(label: string) { + protected emitMark(label: string): void { this.ensureBlankLine(); this.emitLine(`#pragma mark - ${label}`); this.ensureBlankLine(); @@ -846,7 +846,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return camelCaseName; } - private emitPseudoEnumInterface(enumType: EnumType, enumName: Name) { + private emitPseudoEnumInterface(enumType: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(enumType)); this.emitLine("@interface ", enumName, " : NSObject"); @@ -858,7 +858,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - private emitPseudoEnumImplementation(enumType: EnumType, enumName: Name) { + private emitPseudoEnumImplementation(enumType: EnumType, enumName: Name): void { this.emitLine("@implementation ", enumName); const instances = [enumName, ".", staticEnumValuesIdentifier]; @@ -1084,7 +1084,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return iterableSome(this.typeGraph.allTypesUnordered(), needsMap); } - protected emitMapFunction() { + protected emitMapFunction(): void { if (this.needsMap) { this.emitMultiline(`static id map(id collection, id (^f)(id value)) { id result = nil; diff --git a/packages/quicktype-core/src/language/Php.ts b/packages/quicktype-core/src/language/Php.ts index 617f461fe..e448bb1ee 100644 --- a/packages/quicktype-core/src/language/Php.ts +++ b/packages/quicktype-core/src/language/Php.ts @@ -261,7 +261,7 @@ export class PhpRenderer extends ConvenienceRenderer { } protected phpType(_reference: boolean, t: Type, isOptional = false, prefix = "?", suffix = ""): Sourcelike { - function optionalize(s: Sourcelike) { + function optionalize(s: Sourcelike): Sourcelike { return [isOptional ? prefix : "", s, isOptional ? suffix : ""]; } @@ -366,7 +366,7 @@ export class PhpRenderer extends ConvenienceRenderer { ); } - protected phpToObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { + protected phpToObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]): void { matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), @@ -419,7 +419,7 @@ export class PhpRenderer extends ConvenienceRenderer { ); } - private transformDateTime(className: Name, attrName: Sourcelike, scopeAttrName: Sourcelike[]) { + private transformDateTime(className: Name, attrName: Sourcelike, scopeAttrName: Sourcelike[]): void { this.emitBlock(["if (!is_a(", scopeAttrName, ", 'DateTime'))"], () => this.emitLine("throw new Exception('Attribute Error:", className, "::", attrName, "');") ); @@ -428,7 +428,7 @@ export class PhpRenderer extends ConvenienceRenderer { // } } - protected phpFromObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]) { + protected phpFromObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]): void { matchType( t, _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), @@ -491,7 +491,7 @@ export class PhpRenderer extends ConvenienceRenderer { args: Sourcelike[], idx: number, suffix: Sourcelike - ) { + ): void { matchType( t, _anyType => @@ -586,8 +586,8 @@ export class PhpRenderer extends ConvenienceRenderer { ); } - private phpValidate(className: Name, t: Type, attrName: Sourcelike, scopeAttrName: string) { - const is = (isfn: string, myT: Name = className) => { + private phpValidate(className: Name, t: Type, attrName: Sourcelike, scopeAttrName: string): void { + const is = (isfn: string, myT: Name = className): void => { this.emitBlock(["if (!", isfn, "(", scopeAttrName, "))"], () => this.emitLine('throw new Exception("Attribute Error:', myT, "::", attrName, '");') ); @@ -644,7 +644,13 @@ export class PhpRenderer extends ConvenienceRenderer { ); } - protected emitFromMethod(names: FunctionNames, p: ClassProperty, className: Name, _name: Name, desc?: string[]) { + protected emitFromMethod( + names: FunctionNames, + p: ClassProperty, + className: Name, + _name: Name, + desc?: string[] + ): void { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); @@ -672,7 +678,7 @@ export class PhpRenderer extends ConvenienceRenderer { ); } - protected emitToMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitToMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]): void { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); @@ -690,7 +696,13 @@ export class PhpRenderer extends ConvenienceRenderer { }); } - protected emitValidateMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitValidateMethod( + names: FunctionNames, + p: ClassProperty, + className: Name, + name: Name, + desc?: string[] + ): void { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); @@ -710,7 +722,13 @@ export class PhpRenderer extends ConvenienceRenderer { ); } - protected emitGetMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitGetMethod( + names: FunctionNames, + p: ClassProperty, + className: Name, + name: Name, + desc?: string[] + ): void { if (this._options.withGet) { this.emitLine("/**"); if (desc !== undefined) { @@ -746,7 +764,13 @@ export class PhpRenderer extends ConvenienceRenderer { } } - protected emitSetMethod(names: FunctionNames, p: ClassProperty, className: Name, name: Name, desc?: string[]) { + protected emitSetMethod( + names: FunctionNames, + p: ClassProperty, + className: Name, + name: Name, + desc?: string[] + ): void { if (this._options.withSet) { this.emitLine("/**"); if (desc !== undefined) { @@ -772,7 +796,7 @@ export class PhpRenderer extends ConvenienceRenderer { name: Name, desc: string[] | undefined, idx: number - ) { + ): void { if (this._options.withGet) { this.emitLine("/**"); if (desc !== undefined) { @@ -937,11 +961,11 @@ export class PhpRenderer extends ConvenienceRenderer { throw Error("emitUnionDefinition not implemented"); } - protected emitEnumSerializationAttributes(_e: EnumType) { + protected emitEnumSerializationAttributes(_e: EnumType): void { // Empty } - protected emitEnumDeserializationAttributes(_e: EnumType) { + protected emitEnumDeserializationAttributes(_e: EnumType): void { // Empty } diff --git a/packages/quicktype-core/src/language/Pike.ts b/packages/quicktype-core/src/language/Pike.ts index fd2a8b2b9..ea7f9d3a5 100644 --- a/packages/quicktype-core/src/language/Pike.ts +++ b/packages/quicktype-core/src/language/Pike.ts @@ -6,7 +6,7 @@ import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } import { isLetterOrUnderscoreOrDigit, legalizeCharacters, makeNameStyle, stringEscape } from "../support/Strings"; import { TargetLanguage } from "../TargetLanguage"; import { ArrayType, type ClassType, type EnumType, MapType, PrimitiveType, type Type, type UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; +import { type FixMeOptionsAnyType } from "../types"; import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; export const pikeOptions = {}; @@ -256,7 +256,7 @@ export class PikeRenderer extends ConvenienceRenderer { this.emitTable(table); } - private emitInformationComment() { + private emitInformationComment(): void { this.emitCommentLines( [ "This source has been automatically generated by quicktype.", @@ -277,11 +277,11 @@ export class PikeRenderer extends ConvenienceRenderer { ); } - private emitTopLevelTypedef(t: Type, name: Name) { + private emitTopLevelTypedef(t: Type, name: Name): void { this.emitLine("typedef ", this.sourceFor(t).source, " ", name, ";"); } - private emitTopLevelConverter(t: Type, name: Name) { + private emitTopLevelConverter(t: Type, name: Name): void { this.emitBlock([name, " ", name, "_from_JSON(mixed json)"], () => { if (t instanceof PrimitiveType) { this.emitLine(["return json;"]); @@ -302,7 +302,7 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitEncodingFunction(c: ClassType) { + private emitEncodingFunction(c: ClassType): void { this.emitBlock(["string encode_json()"], () => { this.emitMappingBlock(["mapping(string:mixed) json = "], () => { this.forEachClassProperty(c, "none", (name, jsonName) => { @@ -314,7 +314,7 @@ export class PikeRenderer extends ConvenienceRenderer { }); } - private emitDecodingFunction(className: Name, c: ClassType) { + private emitDecodingFunction(className: Name, c: ClassType): void { this.emitBlock([className, " ", className, "_from_JSON(mixed json)"], () => { this.emitLine([className, " retval = ", className, "();"]); this.ensureBlankLine(); diff --git a/packages/quicktype-core/src/language/Python.ts b/packages/quicktype-core/src/language/Python.ts index 37e5106b4..c58dbd852 100644 --- a/packages/quicktype-core/src/language/Python.ts +++ b/packages/quicktype-core/src/language/Python.ts @@ -14,6 +14,7 @@ import { type RenderContext } from "../Renderer"; import { BooleanOption, EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; import { type MultiWord, type Sourcelike, modifySource, multiWord, parenIfNeeded, singleWord } from "../Source"; import { + type WordStyle, allLowerWordStyle, allUpperWordStyle, combineWords, @@ -223,7 +224,7 @@ function classNameStyle(original: string): string { ); } -function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean) { +function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean): WordStyle { if (!forceSnakeNameStyle) { return originalWord; } @@ -1016,7 +1017,7 @@ export class JSONPythonRenderer extends PythonRenderer { } protected transformer(inputTransformer: ValueOrLambda, xfer: Transformer, targetType: Type): ValueOrLambda { - const consume = (consumer: Transformer | undefined, vol: ValueOrLambda) => { + const consume = (consumer: Transformer | undefined, vol: ValueOrLambda): ValueOrLambda => { if (consumer === undefined) { return vol; } diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust.ts index ca36ca6d8..8dcf5b93a 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust.ts @@ -360,7 +360,7 @@ export class RustRenderer extends ConvenienceRenderer { jsonName: string, defaultNamingStyle: string, preferedNamingStyle: string - ) { + ): void { const escapedName = rustStringEscape(jsonName); const name = namingStyles[defaultNamingStyle].fromParts(this.sourcelikeToString(propName).split(" ")); const styledName = nameToNamingStyle(name, preferedNamingStyle); @@ -370,7 +370,7 @@ export class RustRenderer extends ConvenienceRenderer { } } - private emitSkipSerializeNone(t: Type) { + private emitSkipSerializeNone(t: Type): void { if (t instanceof UnionType) { const nullable = nullableFromUnion(t); if (nullable !== null) this.emitLine('#[serde(skip_serializing_if = "Option::is_none")]'); @@ -411,7 +411,7 @@ export class RustRenderer extends ConvenienceRenderer { } const blankLines = this._options.density === Density.Dense ? "none" : "interposing"; - const structBody = () => + const structBody = (): void => this.forEachClassProperty(c, blankLines, (name, jsonName, prop) => { this.emitDescription(this.descriptionForClassProperty(c, jsonName)); this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle); diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts index 69dc3c9fd..cc3ec1b9a 100644 --- a/packages/quicktype-core/src/language/Scala3.ts +++ b/packages/quicktype-core/src/language/Scala3.ts @@ -348,7 +348,7 @@ export class Scala3Renderer extends ConvenienceRenderer { return; } - const scalaType = (p: ClassProperty) => { + const scalaType = (p: ClassProperty): Sourcelike => { if (p.isOptional) { return ["Option[", this.scalaType(p.type, true, true), "]"]; } else { @@ -402,7 +402,7 @@ export class Scala3Renderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(); } - protected emitClassDefinitionMethods() { + protected emitClassDefinitionMethods(): void { this.emitLine(")"); } @@ -489,7 +489,7 @@ export class Scala3Renderer extends ConvenienceRenderer { } export class UpickleRenderer extends Scala3Renderer { - protected emitClassDefinitionMethods() { + protected emitClassDefinitionMethods(): void { this.emitLine(") derives ReadWriter "); } @@ -596,7 +596,7 @@ export class CirceRenderer extends Scala3Renderer { return [wrapOption("Json", optional)]; } - protected emitClassDefinitionMethods() { + protected emitClassDefinitionMethods(): void { this.emitLine(") derives Encoder.AsObject, Decoder"); } diff --git a/packages/quicktype-core/src/language/Smithy4s.ts b/packages/quicktype-core/src/language/Smithy4s.ts index 2abe6f27f..163b33073 100644 --- a/packages/quicktype-core/src/language/Smithy4s.ts +++ b/packages/quicktype-core/src/language/Smithy4s.ts @@ -314,7 +314,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { return; } - const scalaType = (p: ClassProperty) => { + const scalaType = (p: ClassProperty): Sourcelike => { if (p.isOptional) { return [this.scalaType(p.type, true, true)]; } else { @@ -375,7 +375,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(emitLater); } - protected emitClassDefinitionMethods(arrayTypes: ClassProperty[]) { + protected emitClassDefinitionMethods(arrayTypes: ClassProperty[]): void { this.emitLine("}"); arrayTypes.forEach(p => { function ignore(_: T): void { diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift.ts index d46f56780..3991d7f7c 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift.ts @@ -402,7 +402,7 @@ export class SwiftRenderer extends ConvenienceRenderer { else return notJustTypes; } - private get lowerNamingFunction() { + private get lowerNamingFunction(): Namer { return funPrefixNamer("lower", s => swiftNameStyle("", false, s, acronymStyle(this._options.acronymStyle))); } @@ -601,7 +601,7 @@ export class SwiftRenderer extends ConvenienceRenderer { return protocols.length > 0 ? ": " + protocols.join(", ") : ""; } - private getEnumPropertyGroups(c: ClassType) { + private getEnumPropertyGroups(c: ClassType): typeof groups { type PropertyGroup = Array<{ label?: string; name: Name }>; let groups: PropertyGroup[] = []; @@ -699,7 +699,7 @@ export class SwiftRenderer extends ConvenienceRenderer { let lastProperty: ClassProperty | undefined = undefined; let lastNames: Name[] = []; - const emitLastProperty = () => { + const emitLastProperty = (): void => { if (lastProperty === undefined) return; const useMutableProperties = this._options.mutableProperties; @@ -1400,7 +1400,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.endFile(); }; - private emitConvenienceMutator(c: ClassType, className: Name) { + private emitConvenienceMutator(c: ClassType, className: Name): void { this.emitLine("func with("); this.indent(() => { this.forEachClassProperty(c, "none", (name, _, p, position) => { @@ -1431,7 +1431,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } - protected emitMark(line: Sourcelike, horizontalLine = false) { + protected emitMark(line: Sourcelike, horizontalLine = false): void { this.emitLine("// MARK:", horizontalLine ? " - " : " ", line); } @@ -1452,7 +1452,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } } - private emitAlamofireExtension() { + private emitAlamofireExtension(): void { this.ensureBlankLine(); this.emitBlockWithAccess("extension DataRequest", () => { this diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts index 470a79efb..63b35e5db 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts @@ -76,7 +76,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { legalizeName, upper ? firstUpperWordStyle : allLowerWordStyle, firstUpperWordStyle, - upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, + upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", isLetterOrUnderscore @@ -153,7 +153,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { return match; } - private emitObject(name: Name, t: ObjectType) { + private emitObject(name: Name, t: ObjectType): void { this.emittedObjects.add(name); this.ensureBlankLine(); this.emitLine("\nexport class ", name, " extends S.Class<", name, '>("', name, '")({'); @@ -181,10 +181,10 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { } } - protected walkObjectNames(objectType: ObjectType) { + protected walkObjectNames(objectType: ObjectType): Name[] { const names: Name[] = []; - const recurse = (type: Type) => { + const recurse = (type: Type): void => { if (type.kind === "object" || type.kind === "class") { names.push(this.nameForNamedType(type)); this.forEachClassProperty(type as ObjectType, "none", (_, __, prop) => { diff --git a/packages/quicktype-core/src/language/TypeScriptFlow.ts b/packages/quicktype-core/src/language/TypeScriptFlow.ts index a0f6216b3..a6cb60ad8 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow.ts @@ -190,12 +190,12 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } } - private emitClass(c: ClassType, className: Name) { + private emitClass(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitClassBlock(c, className); } - protected emitUnion(u: UnionType, unionName: Name) { + protected emitUnion(u: UnionType, unionName: Name): void { if (!this._tsFlowOptions.declareUnions) { return; } @@ -383,7 +383,7 @@ export class FlowRenderer extends TypeScriptFlowBaseRenderer { }); } - protected emitSourceStructure() { + protected emitSourceStructure(): void { this.emitLine("// @flow"); this.ensureBlankLine(); super.emitSourceStructure(); diff --git a/packages/quicktype-core/src/language/TypeScriptZod.ts b/packages/quicktype-core/src/language/TypeScriptZod.ts index 69cd77fda..ada7494a9 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod.ts @@ -93,7 +93,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { legalizeName, upper ? firstUpperWordStyle : allLowerWordStyle, firstUpperWordStyle, - upper ? s => capitalize(acronyms(s)) : allLowerWordStyle, + upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", isLetterOrUnderscore @@ -169,7 +169,7 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { return match; } - protected emitObject(name: Name, t: ObjectType) { + protected emitObject(name: Name, t: ObjectType): void { this.ensureBlankLine(); this.emitLine("\nexport const ", name, "Schema = ", "z.object({"); this.indent(() => { diff --git a/packages/quicktype-core/src/language/ruby/index.ts b/packages/quicktype-core/src/language/ruby/index.ts index feb6e7608..461a33a94 100644 --- a/packages/quicktype-core/src/language/ruby/index.ts +++ b/packages/quicktype-core/src/language/ruby/index.ts @@ -260,7 +260,7 @@ export class RubyRenderer extends ConvenienceRenderer { } private jsonSample(t: Type): Sourcelike { - function inner() { + function inner(): string { if (t instanceof ArrayType) { return "[…]"; } else if (t instanceof MapType) { @@ -401,14 +401,14 @@ export class RubyRenderer extends ConvenienceRenderer { ); } - private emitBlock(source: Sourcelike, emit: () => void) { + private emitBlock(source: Sourcelike, emit: () => void): void { this.emitLine(source); this.indent(emit); this.emitLine("end"); } - private emitModule(emit: () => void) { - const emitModuleInner = (moduleName: string) => { + private emitModule(emit: () => void): void { + const emitModuleInner = (moduleName: string): void => { const [firstModule, ...subModules] = moduleName.split("::"); if (subModules.length > 0) { this.emitBlock(["module ", firstModule], () => { @@ -426,7 +426,7 @@ export class RubyRenderer extends ConvenienceRenderer { } } - private emitClass(c: ClassType, className: Name) { + private emitClass(c: ClassType, className: Name): void { this.emitDescription(this.descriptionForType(c)); this.emitBlock(["class ", className, " < Dry::Struct"], () => { let table: Sourcelike[][] = []; @@ -518,7 +518,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitEnum(e: EnumType, enumName: Name) { + private emitEnum(e: EnumType, enumName: Name): void { this.emitDescription(this.descriptionForType(e)); this.emitBlock(["module ", enumName], () => { const table: Sourcelike[][] = []; @@ -529,7 +529,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitUnion(u: UnionType, unionName: Name) { + private emitUnion(u: UnionType, unionName: Name): void { this.emitDescription(this.descriptionForType(u)); this.emitBlock(["class ", unionName, " < Dry::Struct"], () => { const table: Sourcelike[][] = []; @@ -601,7 +601,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - private emitTypesModule() { + private emitTypesModule(): void { this.emitBlock(["module Types"], () => { this.emitLine("include Dry.Types(default: :nominal)"); @@ -649,7 +649,7 @@ export class RubyRenderer extends ConvenienceRenderer { }); } - protected emitSourceStructure() { + protected emitSourceStructure(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else if (!this._options.justTypes) { @@ -704,7 +704,7 @@ export class RubyRenderer extends ConvenienceRenderer { // it for arrays. const needsToJsonDefined = "array" === topLevel.kind; - const classDeclaration = () => { + const classDeclaration = (): void => { this.emitBlock(["class ", name], () => { this.emitBlock(["def self.from_json!(json)"], () => { if (needsToJsonDefined) { diff --git a/packages/quicktype-core/src/support/Acronyms.ts b/packages/quicktype-core/src/support/Acronyms.ts index 8c3eabcf1..d24c85e97 100644 --- a/packages/quicktype-core/src/support/Acronyms.ts +++ b/packages/quicktype-core/src/support/Acronyms.ts @@ -1108,7 +1108,7 @@ export enum AcronymStyleOptions { Pascal = "pascal" } -export const acronymOption = function (defaultOption: AcronymStyleOptions) { +export const acronymOption = function (defaultOption: AcronymStyleOptions): EnumOption { return new EnumOption( "acronym-style", "Acronym naming style", diff --git a/packages/quicktype-core/src/support/Converters.ts b/packages/quicktype-core/src/support/Converters.ts index 1e9a46250..caec348bf 100644 --- a/packages/quicktype-core/src/support/Converters.ts +++ b/packages/quicktype-core/src/support/Converters.ts @@ -5,7 +5,7 @@ export enum ConvertersOptions { TopLevel = "top-level" } -export function convertersOption() { +export function convertersOption(): EnumOption { return new EnumOption( "converters", "Which converters to generate (top-level by default)", diff --git a/src/index.ts b/src/index.ts index 5006b0bde..7efee1f87 100644 --- a/src/index.ts +++ b/src/index.ts @@ -201,7 +201,7 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr } // FIXME: rewrite this to be clearer - const oneUnlessEmpty = (xs: TypeSource[]) => Math.sign(xs.length); + const oneUnlessEmpty = (xs: TypeSource[]): 0 | 1 => Math.sign(xs.length) as 0 | 1; if (oneUnlessEmpty(schemaSources) + oneUnlessEmpty(graphQLSources) > 1) { return messageError("DriverCannotMixNonJSONInputs", { dir: dir }); } @@ -629,7 +629,7 @@ function parseOptions(definitions: OptionDefinition[], argv: string[], partial: return options; } -function usage(targetLanguages: TargetLanguage[]) { +function usage(targetLanguages: TargetLanguage[]): void { const rendererSections: UsageSection[] = []; for (const language of targetLanguages) { @@ -978,7 +978,7 @@ export function writeOutput( } } -export async function main(args: string[] | Partial) { +export async function main(args: string[] | Partial): Promise { let cliOptions: CLIOptions; if (Array.isArray(args)) { cliOptions = parseCLIOptions(args); From e5edac4b8d278906aa5fc2e6d8aaf17c7a037aaa Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 21:20:23 -0700 Subject: [PATCH 27/80] fix types errors --- .../quicktype-core/src/input/Inference.ts | 5 +- packages/quicktype-core/src/language/CJSON.ts | 47 ++++++++++++++++++- packages/quicktype-core/src/language/Swift.ts | 2 +- .../quicktype-core/src/support/Support.ts | 3 +- src/index.ts | 6 ++- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/quicktype-core/src/input/Inference.ts b/packages/quicktype-core/src/input/Inference.ts index a8dc6a772..85c544c7b 100644 --- a/packages/quicktype-core/src/input/Inference.ts +++ b/packages/quicktype-core/src/input/Inference.ts @@ -20,8 +20,9 @@ import { type CompressedJSON, Tag, type Value, valueTag } from "./CompressedJSON // This should be the recursive type // Value[] | NestedValueArray[] // but TypeScript doesn't support that. -// FIXME -export type NestedValueArray = Value[]; +// FIXME: reactor this +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type NestedValueArray = any; function forEachArrayInNestedValueArray(va: NestedValueArray, f: (va: Value[]) => void): void { if (va.length === 0) { diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON.ts index 3cfe6b976..28499a4b4 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON.ts @@ -498,7 +498,7 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param fieldType: the variable type * @param fieldName: name of the variable */ - protected emitTypedefAlias(fieldType: Type, fieldName: Name) { + protected emitTypedefAlias(fieldType: Type, fieldName: Name): void { if (this._options.addTypedefAlias) { this.emitLine("typedef ", this.quicktypeTypeToCJSON(fieldType, false).cType, " ", fieldName, ";"); this.ensureBlankLine(); @@ -922,6 +922,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", @@ -936,6 +937,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", + // @ts-expect-error awaiting refactor cJSON.items?.getValue, "(e", child_level.toString(), @@ -947,6 +949,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ", tmp", level > 0 ? level.toString() : "", ", sizeof(", + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *));" ); @@ -1057,6 +1060,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", @@ -1071,6 +1075,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", + // @ts-expect-error awaiting refactor cJSON.items?.getValue, "(e", child_level.toString(), @@ -1084,6 +1089,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "->string, tmp", level > 0 ? level.toString() : "", ", sizeof(", + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *));" ); @@ -1185,6 +1191,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * x", child_level.toString(), @@ -1229,6 +1236,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "cJSON_AddItemToArray(j", child_level.toString(), ", ", + // @ts-expect-error awaiting refactor cJSON.items?.createObject, "(*x", child_level.toString(), @@ -1305,6 +1313,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *x", child_level.toString(), @@ -1367,6 +1376,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", + // @ts-expect-error awaiting refactor cJSON.items?.createObject, "(*x", child_level.toString(), @@ -1450,6 +1460,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * x", child_level.toString(), @@ -1475,6 +1486,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -1484,6 +1496,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -1551,6 +1564,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *x", child_level.toString(), @@ -1584,6 +1598,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -1593,6 +1608,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -1766,6 +1782,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ", x", child_level2.toString(), ", sizeof(", + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *));" ); @@ -1965,6 +1982,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", @@ -1983,6 +2001,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", + // @ts-expect-error awaiting refactor cJSON.items?.getValue, "(e", child_level.toString(), @@ -1994,6 +2013,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ", tmp", level > 0 ? level.toString() : "", ", sizeof(", + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *));" ); @@ -2139,6 +2159,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * tmp", level > 0 ? level.toString() : "", @@ -2157,6 +2178,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "* tmp", level > 0 ? level.toString() : "", " = ", + // @ts-expect-error awaiting refactor cJSON.items?.getValue, "(e", child_level.toString(), @@ -2170,6 +2192,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "->string, tmp", level > 0 ? level.toString() : "", ", sizeof(", + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *));" ); @@ -2478,6 +2501,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * x", child_level.toString(), @@ -2540,6 +2564,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "cJSON_AddItemToArray(j", child_level.toString(), ", ", + // @ts-expect-error awaiting refactor cJSON.items?.createObject, "(*x", child_level.toString(), @@ -2626,6 +2651,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *x", child_level.toString(), @@ -2715,6 +2741,7 @@ export class CJSONRenderer extends ConvenienceRenderer { "[index", child_level.toString(), "], ", + // @ts-expect-error awaiting refactor cJSON.items?.createObject, "(*x", child_level.toString(), @@ -3015,6 +3042,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " * x", child_level.toString(), @@ -3050,6 +3078,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -3059,6 +3088,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -3119,6 +3149,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *x", child_level.toString(), @@ -3164,6 +3195,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -3173,6 +3205,7 @@ export class CJSONRenderer extends ConvenienceRenderer { ); } else { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.deleteType, "(x", child_level.toString(), @@ -3376,6 +3409,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { this.emitLine( "list_add_tail(x->value, ", + // @ts-expect-error awaiting refactor cJSON.items?.getValue, "(e), sizeof(", cJSON.items?.cType, @@ -3430,6 +3464,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { this.emitLine( "hashtable_add(x->value, e->string, ", + // @ts-expect-error awaiting refactor cJSON.items?.getValue, "(e), sizeof(", cJSON.items?.cType, @@ -3479,6 +3514,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["if (NULL != x->value)"], () => { this.emitLine("j = ", cJSON.createObject, "();"); this.emitBlock(["if (NULL != j)"], () => { + // @ts-expect-error awaiting refactor this.emitLine(cJSON.items?.cType, " * x1 = list_get_head(x->value);"); this.emitBlock(["while (NULL != x1)"], () => { const add = (cJSON: TypeCJSON) => { @@ -3507,6 +3543,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { this.emitLine( "cJSON_AddItemToArray(j, ", + // @ts-expect-error awaiting refactor cJSON.items?.createObject, "(*x1));" ); @@ -3537,6 +3574,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock(["if (NULL != keys)"], () => { this.emitBlock(["for (size_t index = 0; index < count; index++)"], () => { this.emitLine( + // @ts-expect-error awaiting refactor cJSON.items?.cType, " *x2 = hashtable_lookup(x->value, keys[index]);" ); @@ -3569,6 +3607,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine( cJSON.addToObject, "(j, keys[index], ", + // @ts-expect-error awaiting refactor cJSON.items?.createObject, "(*x2));" ); @@ -3626,13 +3665,16 @@ export class CJSONRenderer extends ConvenienceRenderer { const cJSON = this.quicktypeTypeToCJSON(type, false); if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { this.emitBlock(["if (NULL != x->value)"], () => { + // @ts-expect-error awaiting refactor this.emitLine(cJSON.items?.cType, " * x1 = list_get_head(x->value);"); this.emitBlock(["while (NULL != x1)"], () => { if (cJSON.items?.isNullable) { this.emitBlock(["if ((void *)0xDEADBEEF != x1)"], () => { + // @ts-expect-error awaiting refactor this.emitLine(cJSON.items?.deleteType, "(x1);"); }); } else { + // @ts-expect-error awaiting refactor this.emitLine(cJSON.items?.deleteType, "(x1);"); } @@ -3646,13 +3688,16 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitLine("size_t count = hashtable_get_keys(x->value, &keys);"); this.emitBlock(["if (NULL != keys)"], () => { this.emitBlock(["for (size_t index = 0; index < count; index++)"], () => { + // @ts-expect-error awaiting refactor this.emitLine(cJSON.items?.cType, " *x2 = hashtable_lookup(x->value, keys[index]);"); this.emitBlock(["if (NULL != x2)"], () => { if (cJSON.items?.isNullable) { this.emitBlock(["if ((", cJSON.items?.cType, " *)0xDEADBEEF != x2)"], () => { + // @ts-expect-error awaiting refactor this.emitLine(cJSON.items?.deleteType, "(x2);"); }); } else { + // @ts-expect-error awaiting refactor this.emitLine(cJSON.items?.deleteType, "(x2);"); } }); diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift.ts index 3991d7f7c..661d6655f 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift.ts @@ -730,7 +730,7 @@ export class SwiftRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (name, jsonName, p) => { const description = this.descriptionForClassProperty(c, jsonName); if ( - !p.equals(lastProperty) || + (lastProperty && !p.equals(lastProperty)) || lastNames.length >= MAX_SAMELINE_PROPERTIES || description !== undefined ) { diff --git a/packages/quicktype-core/src/support/Support.ts b/packages/quicktype-core/src/support/Support.ts index 3778ed3ed..3715a7108 100644 --- a/packages/quicktype-core/src/support/Support.ts +++ b/packages/quicktype-core/src/support/Support.ts @@ -2,6 +2,7 @@ import { Base64 } from "js-base64"; import * as pako from "pako"; import * as YAML from "yaml"; +import { type JSONSchema } from "../input/JSONSchemaStore"; import { messageError } from "../Messages"; export interface StringMap { @@ -123,7 +124,7 @@ export function inflateBase64(encoded: string): string { return pako.inflate(bytes, { to: "string" }); } -export function parseJSON(text: string, description: string, address = ""): unknown { +export function parseJSON(text: string, description: string, address = ""): JSONSchema | undefined { try { // https://gist.github.com/pbakondy/f5045eff725193dad9c7 if (text.charCodeAt(0) === 0xfeff) { diff --git a/src/index.ts b/src/index.ts index 7efee1f87..fe252a087 100644 --- a/src/index.ts +++ b/src/index.ts @@ -752,7 +752,11 @@ async function makeInputData( } function stringSourceDataToStreamSourceData(src: JSONSourceData): JSONSourceData { - return { name: src.name, description: src.description, samples: src.samples.map(stringToStream) }; + return { + name: src.name, + description: src.description, + samples: src.samples.map(sample => stringToStream(sample) as Readable) + }; } export async function makeQuicktypeOptions( From 130fe313500d16a045a193b46832f6b281dff46f Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 08:34:03 -0700 Subject: [PATCH 28/80] fix json import for test tsconfig --- test/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tsconfig.json b/test/tsconfig.json index 26618760c..a042b47f7 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -4,7 +4,8 @@ "strict": true, "alwaysStrict": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "resolveJsonModule": true }, "include": ["*.ts", "../dist/*.js", "../dist/*.d.ts"] } From 06002f9ed70250878e146030d5040d7ce9e96650 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 07:56:48 -0700 Subject: [PATCH 29/80] auto lint fix --- packages/quicktype-core/src/language/Swift.ts | 1 + .../quicktype-typescript-input/src/index.ts | 4 +- packages/quicktype-vscode/src/extension.ts | 82 +++++++++++-------- 3 files changed, 53 insertions(+), 34 deletions(-) diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift.ts index 56e4f89d4..e16ba1cb2 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift.ts @@ -773,6 +773,7 @@ export class SwiftRenderer extends ConvenienceRenderer { enumDeclaration += ", "; enumDeclaration += this._options.codingKeysProtocol; } + this.emitBlock(enumDeclaration, () => { for (const group of groups) { const { name, label } = group[0]; diff --git a/packages/quicktype-typescript-input/src/index.ts b/packages/quicktype-typescript-input/src/index.ts index b8ebc7f89..3289e914b 100644 --- a/packages/quicktype-typescript-input/src/index.ts +++ b/packages/quicktype-typescript-input/src/index.ts @@ -34,13 +34,13 @@ export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchem const schema = generateSchema(program, "*", settings); const uris: string[] = []; - let topLevelName: string = ""; + let topLevelName = ""; // if there is a type that is `export default`, swap the corresponding ref if (schema?.definitions?.default) { const defaultDefinition = schema?.definitions?.default; const matchingDefaultName = Object.entries(schema?.definitions ?? {}).find( - ([_name, definition]) => (definition as Record)["$ref"] === "#/definitions/default" + ([_name, definition]) => (definition as Record).$ref === "#/definitions/default" )?.[0]; if (matchingDefaultName) { diff --git a/packages/quicktype-vscode/src/extension.ts b/packages/quicktype-vscode/src/extension.ts index 3c62a47d2..f6c202748 100644 --- a/packages/quicktype-vscode/src/extension.ts +++ b/packages/quicktype-vscode/src/extension.ts @@ -2,22 +2,24 @@ import * as path from "path"; -import * as vscode from "vscode"; -import { Range } from "vscode"; import { - quicktype, - languageNamed, - SerializedRenderResult, - defaultTargetLanguages, - JSONSchemaInput, InputData, - TargetLanguage, + JSONSchemaInput, + defaultTargetLanguages, + inferenceFlagNames, jsonInputForTargetLanguage, - RendererOptions, - Options, - inferenceFlagNames + languageNamed, + quicktype } from "quicktype-core"; +import { + type Options, + type RendererOptions, + type SerializedRenderResult, + type TargetLanguage} from "quicktype-core"; import { schemaForTypeScriptSources } from "quicktype-typescript-input"; +import * as vscode from "vscode"; +import { Range } from "vscode"; + const configurationSection = "quicktype"; @@ -39,6 +41,7 @@ function jsonIsValid(json: string) { } catch (e) { return false; } + return true; } @@ -53,10 +56,10 @@ async function promptTopLevelName(): Promise<{ cancelled: boolean; name: string }; } -type TargetLanguagePick = { +interface TargetLanguagePick { cancelled: boolean; lang: TargetLanguage; -}; +} async function pickTargetLanguage(): Promise { const languageChoices = defaultTargetLanguages.map(l => l.displayName).sort(); @@ -65,6 +68,7 @@ async function pickTargetLanguage(): Promise { if (chosenName === undefined) { chosenName = "typescript"; } + return { cancelled, lang: languageNamed(chosenName)! }; } @@ -77,6 +81,7 @@ async function getTargetLanguage(editor: vscode.TextEditor): Promise(); + private readonly _changeSubscription: vscode.Disposable; + private readonly _onDidChangeVisibleTextEditors: vscode.Disposable; + private readonly _onDidChangeConfiguration: vscode.Disposable; private _isOpen = false; + private _timer: NodeJS.Timeout | undefined = undefined; constructor( @@ -279,6 +291,7 @@ class CodeProvider implements vscode.TextDocumentContentProvider { if (!this._isOpen && isOpen) { this.update(); } + this._isOpen = isOpen; } @@ -296,6 +309,7 @@ class CodeProvider implements vscode.TextDocumentContentProvider { if (this._timer) { clearTimeout(this._timer); } + this._timer = setTimeout(() => { this._timer = undefined; this.update(); @@ -338,14 +352,17 @@ function deduceTargetLanguage(): TargetLanguage { if (count === undefined) { count = 0; } + count += 1; counts.set(name, count); } + const sorted = Array.from(counts).sort(([_na, ca], [_nb, cb]) => cb - ca); for (const [name] of sorted) { const lang = languageNamed(name); if (lang !== undefined) return lang; } + return languageNamed("typescript")!; } @@ -382,12 +399,13 @@ async function openQuicktype( const doc = lastCodeProvider.document; originalEditor = vscode.window.visibleTextEditors.find(e => e.document === doc); } + if (originalEditor === undefined) { originalEditor = vscode.window.activeTextEditor; } let column: number; - if (originalEditor !== undefined && originalEditor.viewColumn !== undefined) { + if (originalEditor?.viewColumn !== undefined) { column = originalEditor.viewColumn + 1; } else { column = 0; @@ -422,29 +440,29 @@ export async function activate(context: vscode.ExtensionContext): Promise extensionContext = context; context.subscriptions.push( - vscode.commands.registerTextEditorCommand(Command.PasteJSONAsTypes, editor => - pasteAsTypes(editor, "json", true) + vscode.commands.registerTextEditorCommand(Command.PasteJSONAsTypes, async editor => + await pasteAsTypes(editor, "json", true) ), - vscode.commands.registerTextEditorCommand(Command.PasteJSONAsTypesAndSerialization, editor => - pasteAsTypes(editor, "json", false) + vscode.commands.registerTextEditorCommand(Command.PasteJSONAsTypesAndSerialization, async editor => + await pasteAsTypes(editor, "json", false) ), - vscode.commands.registerTextEditorCommand(Command.PasteSchemaAsTypes, editor => - pasteAsTypes(editor, "schema", true) + vscode.commands.registerTextEditorCommand(Command.PasteSchemaAsTypes, async editor => + await pasteAsTypes(editor, "schema", true) ), - vscode.commands.registerTextEditorCommand(Command.PasteSchemaAsTypesAndSerialization, editor => - pasteAsTypes(editor, "schema", false) + vscode.commands.registerTextEditorCommand(Command.PasteSchemaAsTypesAndSerialization, async editor => + await pasteAsTypes(editor, "schema", false) ), - vscode.commands.registerTextEditorCommand(Command.PasteTypeScriptAsTypesAndSerialization, editor => - pasteAsTypes(editor, "typescript", false) + vscode.commands.registerTextEditorCommand(Command.PasteTypeScriptAsTypesAndSerialization, async editor => + await pasteAsTypes(editor, "typescript", false) ), - vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForJSON, editor => - openForEditor(editor, "json") + vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForJSON, async editor => + await openForEditor(editor, "json") ), - vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForJSONSchema, editor => - openForEditor(editor, "schema") + vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForJSONSchema, async editor => + await openForEditor(editor, "schema") ), - vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForTypeScript, editor => - openForEditor(editor, "typescript") + vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForTypeScript, async editor => + await openForEditor(editor, "typescript") ), vscode.commands.registerCommand(Command.ChangeTargetLanguage, changeTargetLanguage) ); From 93ab86e0923bfde02c4f362d3d06e842f9f834be Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 08:04:54 -0700 Subject: [PATCH 30/80] fix lint errors in extension --- packages/quicktype-vscode/src/extension.ts | 133 +++++++++++---------- 1 file changed, 73 insertions(+), 60 deletions(-) diff --git a/packages/quicktype-vscode/src/extension.ts b/packages/quicktype-vscode/src/extension.ts index f6c202748..3e8083721 100644 --- a/packages/quicktype-vscode/src/extension.ts +++ b/packages/quicktype-vscode/src/extension.ts @@ -5,21 +5,19 @@ import * as path from "path"; import { InputData, JSONSchemaInput, + type Options, + type RendererOptions, + type SerializedRenderResult, + type TargetLanguage, defaultTargetLanguages, inferenceFlagNames, jsonInputForTargetLanguage, languageNamed, quicktype } from "quicktype-core"; -import { - type Options, - type RendererOptions, - type SerializedRenderResult, - type TargetLanguage} from "quicktype-core"; import { schemaForTypeScriptSources } from "quicktype-typescript-input"; +// eslint-disable-next-line import/no-unresolved import * as vscode from "vscode"; -import { Range } from "vscode"; - const configurationSection = "quicktype"; @@ -35,7 +33,7 @@ enum Command { ChangeTargetLanguage = "quicktype.changeTargetLanguage" } -function jsonIsValid(json: string) { +function jsonIsValid(json: string): boolean { try { JSON.parse(json); } catch (e) { @@ -52,6 +50,7 @@ async function promptTopLevelName(): Promise<{ cancelled: boolean; name: string return { cancelled: topLevelName === undefined, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing name: topLevelName || "TopLevel" }; } @@ -69,7 +68,8 @@ async function pickTargetLanguage(): Promise { chosenName = "typescript"; } - return { cancelled, lang: languageNamed(chosenName)! }; + // @ts-expect-error languageNamed is not strongly typed yet + return { cancelled, lang: languageNamed(chosenName) }; } async function getTargetLanguage(editor: vscode.TextEditor): Promise { @@ -154,7 +154,7 @@ async function runQuicktype( return await quicktype(options); } -async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justTypes: boolean) { +async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justTypes: boolean): Promise { let indentation: string; if (editor.options.insertSpaces) { const tabSize = editor.options.tabSize as number; @@ -172,13 +172,11 @@ async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justType try { content = await vscode.env.clipboard.readText(); } catch (e) { - vscode.window.showErrorMessage("Could not get clipboard contents"); - return; + return await vscode.window.showErrorMessage("Could not get clipboard contents"); } if (kind !== "typescript" && !jsonIsValid(content)) { - vscode.window.showErrorMessage("Clipboard does not contain valid JSON."); - return; + return await vscode.window.showErrorMessage("Clipboard does not contain valid JSON."); } let topLevelName: string; @@ -196,28 +194,30 @@ async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justType let result: SerializedRenderResult; try { result = await runQuicktype(content, kind, language.lang, topLevelName, justTypes, indentation); - } catch (e: any) { + } catch (e) { // TODO Invalid JSON produces an uncatchable exception from quicktype // Fix this so we can catch and show an error message. - vscode.window.showErrorMessage(e); - return; + if (typeof e === "string") { + return await vscode.window.showErrorMessage(e); + } } + // @ts-expect-error FIXME: resolve this after above ^ const text = result.lines.join("\n"); const selection = editor.selection; - editor.edit(builder => { + return await editor.edit(builder => { if (selection.isEmpty) { builder.insert(selection.start, text); } else { - builder.replace(new Range(selection.start, selection.end), text); + builder.replace(new vscode.Range(selection.start, selection.end), text); } }); } class CodeProvider implements vscode.TextDocumentContentProvider { - readonly scheme: string = "quicktype"; + public readonly scheme: string = "quicktype"; - readonly uri: vscode.Uri; + public readonly uri: vscode.Uri; private _documentText: string = "{}"; @@ -235,7 +235,7 @@ class CodeProvider implements vscode.TextDocumentContentProvider { private _timer: NodeJS.Timeout | undefined = undefined; - constructor( + public constructor( private _inputKind: InputKind, private readonly _targetLanguage: TargetLanguage, private _document: vscode.TextDocument @@ -253,43 +253,43 @@ class CodeProvider implements vscode.TextDocumentContentProvider { ); } - dispose(): void { + public dispose(): void { this._onDidChange.dispose(); this._changeSubscription.dispose(); this._onDidChangeVisibleTextEditors.dispose(); this._onDidChangeConfiguration.dispose(); } - get inputKind(): InputKind { + public get inputKind(): InputKind { return this._inputKind; } - setInputKind(inputKind: InputKind): void { + public setInputKind(inputKind: InputKind): void { this._inputKind = inputKind; } - get document(): vscode.TextDocument { + public get document(): vscode.TextDocument { return this._document; } - get documentName(): string { + public get documentName(): string { const basename = path.basename(this.document.fileName); const extIndex = basename.lastIndexOf("."); return extIndex === -1 ? basename : basename.substring(0, extIndex); } - setDocument(document: vscode.TextDocument): void { + public setDocument(document: vscode.TextDocument): void { this._document = document; } - get onDidChange(): vscode.Event { + public get onDidChange(): vscode.Event { return this._onDidChange.event; } - private visibleTextEditorsDidChange(editors: vscode.TextEditor[]) { + private visibleTextEditorsDidChange(editors: vscode.TextEditor[]): void { const isOpen = editors.some(e => e.document.uri.scheme === this.scheme); if (!this._isOpen && isOpen) { - this.update(); + void this.update(); } this._isOpen = isOpen; @@ -297,7 +297,7 @@ class CodeProvider implements vscode.TextDocumentContentProvider { private configurationDidChange(ev: vscode.ConfigurationChangeEvent): void { if (ev.affectsConfiguration(configurationSection)) { - this.update(); + void this.update(); } } @@ -312,11 +312,11 @@ class CodeProvider implements vscode.TextDocumentContentProvider { this._timer = setTimeout(() => { this._timer = undefined; - this.update(); + void this.update(); }, 300); } - async update(): Promise { + public async update(): Promise { this._documentText = this._document.getText(); try { @@ -333,10 +333,15 @@ class CodeProvider implements vscode.TextDocumentContentProvider { if (!this._isOpen) return; this._onDidChange.fire(this.uri); - } catch (e) {} + } catch (e) { + // FIXME + } } - provideTextDocumentContent(_uri: vscode.Uri, _token: vscode.CancellationToken): vscode.ProviderResult { + public provideTextDocumentContent( + _uri: vscode.Uri, + _token: vscode.CancellationToken + ): vscode.ProviderResult { this._isOpen = true; return this._targetCode; @@ -363,7 +368,8 @@ function deduceTargetLanguage(): TargetLanguage { if (lang !== undefined) return lang; } - return languageNamed("typescript")!; + // @ts-expect-error languageNamed is not yet strongly typed + return languageNamed("typescript"); } const lastTargetLanguageUsedKey = "lastTargetLanguageUsed"; @@ -379,7 +385,7 @@ async function openQuicktype( inputKind: InputKind, targetLanguage: TargetLanguage, document: vscode.TextDocument -): Promise { +): Promise { let codeProvider = codeProviders.get(targetLanguage.name); if (codeProvider === undefined) { codeProvider = new CodeProvider(inputKind, targetLanguage, document); @@ -396,8 +402,8 @@ async function openQuicktype( let originalEditor: vscode.TextEditor | undefined; if (lastCodeProvider !== undefined) { - const doc = lastCodeProvider.document; - originalEditor = vscode.window.visibleTextEditors.find(e => e.document === doc); + const lastDoc = lastCodeProvider.document; + originalEditor = vscode.window.visibleTextEditors.find(e => e.document === lastDoc); } if (originalEditor === undefined) { @@ -413,14 +419,13 @@ async function openQuicktype( lastCodeProvider = codeProvider; - codeProvider.update(); + await codeProvider.update(); const doc = await vscode.workspace.openTextDocument(codeProvider.uri); - vscode.window.showTextDocument(doc, column, true); + return await vscode.window.showTextDocument(doc, column, true); } async function openForEditor(editor: vscode.TextEditor, inputKind: InputKind): Promise { - const targetLanguage = - explicitlySetTargetLanguage !== undefined ? explicitlySetTargetLanguage : deduceTargetLanguage(); + const targetLanguage = explicitlySetTargetLanguage ?? deduceTargetLanguage(); await openQuicktype(inputKind, targetLanguage, editor.document); } @@ -440,29 +445,37 @@ export async function activate(context: vscode.ExtensionContext): Promise extensionContext = context; context.subscriptions.push( - vscode.commands.registerTextEditorCommand(Command.PasteJSONAsTypes, async editor => - await pasteAsTypes(editor, "json", true) + vscode.commands.registerTextEditorCommand( + Command.PasteJSONAsTypes, + async editor => await pasteAsTypes(editor, "json", true) ), - vscode.commands.registerTextEditorCommand(Command.PasteJSONAsTypesAndSerialization, async editor => - await pasteAsTypes(editor, "json", false) + vscode.commands.registerTextEditorCommand( + Command.PasteJSONAsTypesAndSerialization, + async editor => await pasteAsTypes(editor, "json", false) ), - vscode.commands.registerTextEditorCommand(Command.PasteSchemaAsTypes, async editor => - await pasteAsTypes(editor, "schema", true) + vscode.commands.registerTextEditorCommand( + Command.PasteSchemaAsTypes, + async editor => await pasteAsTypes(editor, "schema", true) ), - vscode.commands.registerTextEditorCommand(Command.PasteSchemaAsTypesAndSerialization, async editor => - await pasteAsTypes(editor, "schema", false) + vscode.commands.registerTextEditorCommand( + Command.PasteSchemaAsTypesAndSerialization, + async editor => await pasteAsTypes(editor, "schema", false) ), - vscode.commands.registerTextEditorCommand(Command.PasteTypeScriptAsTypesAndSerialization, async editor => - await pasteAsTypes(editor, "typescript", false) + vscode.commands.registerTextEditorCommand( + Command.PasteTypeScriptAsTypesAndSerialization, + async editor => await pasteAsTypes(editor, "typescript", false) ), - vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForJSON, async editor => - await openForEditor(editor, "json") + vscode.commands.registerTextEditorCommand( + Command.OpenQuicktypeForJSON, + async editor => await openForEditor(editor, "json") ), - vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForJSONSchema, async editor => - await openForEditor(editor, "schema") + vscode.commands.registerTextEditorCommand( + Command.OpenQuicktypeForJSONSchema, + async editor => await openForEditor(editor, "schema") ), - vscode.commands.registerTextEditorCommand(Command.OpenQuicktypeForTypeScript, async editor => - await openForEditor(editor, "typescript") + vscode.commands.registerTextEditorCommand( + Command.OpenQuicktypeForTypeScript, + async editor => await openForEditor(editor, "typescript") ), vscode.commands.registerCommand(Command.ChangeTargetLanguage, changeTargetLanguage) ); From 1ec5933c783db7f7e57286bb2a1bac41bf231c73 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 08:25:03 -0700 Subject: [PATCH 31/80] fix lint errors in Elixir --- .../quicktype-core/src/language/Elixir.ts | 83 +++++++++++-------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/packages/quicktype-core/src/language/Elixir.ts b/packages/quicktype-core/src/language/Elixir.ts index ddbbcdaa7..f864e2a93 100644 --- a/packages/quicktype-core/src/language/Elixir.ts +++ b/packages/quicktype-core/src/language/Elixir.ts @@ -1,27 +1,27 @@ import unicode from "unicode-properties"; -import { Sourcelike } from "../Source"; -import { Namer, Name } from "../Naming"; -import { ConvenienceRenderer, ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { TargetLanguage } from "../TargetLanguage"; -import { Option, BooleanOption, OptionValues, getOptionValues, StringOption } from "../RendererOptions"; -import { Type, EnumType, ClassType, UnionType, ArrayType, MapType, PrimitiveType } from "../Type"; -import { matchType, nullableFromUnion } from "../TypeUtils"; - +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; +import { type Name, Namer } from "../Naming"; +import { type RenderContext } from "../Renderer"; +import { BooleanOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; +import { type Sourcelike } from "../Source"; import { - legalizeCharacters, - splitIntoWords, - combineWords, - firstUpperWordStyle, - allUpperWordStyle, allLowerWordStyle, - utf32ConcatMap, - isPrintable, + allUpperWordStyle, + combineWords, escapeNonPrintableMapper, + firstUpperWordStyle, intToHex, - isLetterOrUnderscore + isLetterOrUnderscore, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap } from "../support/Strings"; -import { RenderContext } from "../Renderer"; +import { TargetLanguage } from "../TargetLanguage"; +import { ArrayType, ClassType, EnumType, MapType, PrimitiveType, type Type, UnionType } from "../Type"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; +import { matchType, nullableFromUnion } from "../TypeUtils"; const forbiddenModuleNames = [ "Access", @@ -128,17 +128,17 @@ function unicodeEscape(codePoint: number): string { return `\\u{${intToHex(codePoint, 0)}}`; } -function capitalizeFirstLetter(str: string) { +function capitalizeFirstLetter(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); -function escapeDoubleQuotes(str: string) { +function escapeDoubleQuotes(str: string): string { return str.replace(/"/g, '\\"'); } -function escapeNewLines(str: string) { +function escapeNewLines(str: string): string { return str.replace(/\n/g, "\\n"); } @@ -148,15 +148,15 @@ export const elixirOptions = { }; export class ElixirTargetLanguage extends TargetLanguage { - constructor() { + public constructor() { super("Elixir", ["elixir"], "ex"); } - protected getOptions(): Option[] { + protected getOptions(): Array> { return [elixirOptions.justTypes, elixirOptions.namespace]; } - get supportsOptionalClassProperties(): boolean { + public get supportsOptionalClassProperties(): boolean { return true; } @@ -164,7 +164,7 @@ export class ElixirTargetLanguage extends TargetLanguage { return " "; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: { [name: string]: any }): ElixirRenderer { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ElixirRenderer { return new ElixirRenderer(this, renderContext, getOptionValues(elixirOptions, untypedOptionValues)); } } @@ -173,7 +173,7 @@ const isStartCharacter = isLetterOrUnderscore; function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } const legalizeName = legalizeCharacters(isPartCharacter); @@ -182,6 +182,7 @@ function simpleNameStyle(original: string, uppercase: boolean): string { if (/^[0-9]+$/.test(original)) { original = `${original}N`; } + const words = splitIntoWords(original); return combineWords( words, @@ -210,7 +211,7 @@ function memberNameStyle(original: string): string { } export class ElixirRenderer extends ConvenienceRenderer { - constructor( + public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, private readonly _options: OptionValues @@ -285,7 +286,7 @@ export class ElixirRenderer extends ConvenienceRenderer { mapType => ["%{String.t() => ", this.elixirType(mapType.values), "}", optional], enumType => [this.nameForNamedTypeWithNamespace(enumType), ".t()", optional], unionType => { - const children = [...unionType.getChildren()].map(t => this.elixirType(t)); + const children = [...unionType.getChildren()].map(ut => this.elixirType(ut)); return [ children.flatMap((element, index) => (index === children.length - 1 ? element : [element, " | "])), optional @@ -422,7 +423,13 @@ export class ElixirRenderer extends ConvenienceRenderer { }); } - private emitPatternMatches(types: Type[], name: Sourcelike, parentName: Sourcelike, suffix = "", optional = false) { + private emitPatternMatches( + types: Type[], + name: Sourcelike, + parentName: Sourcelike, + suffix = "", + optional = false + ): void { this.ensureBlankLine(); let typesToMatch = this.sortAndFilterPatternMatchTypes(types); @@ -482,6 +489,7 @@ export class ElixirRenderer extends ConvenienceRenderer { if (encode) { mode = "encode"; } + return matchType( t, _anyType => [], @@ -574,6 +582,7 @@ export class ElixirRenderer extends ConvenienceRenderer { "(value)} end)" ]; } + return [primitive]; } }, @@ -604,8 +613,10 @@ export class ElixirRenderer extends ConvenienceRenderer { if (nullableTypes.length < 2) { return this.fromDynamic(nullable, jsonName, name, true); } + return ['m["', jsonName, '"] && decode_', name, '(m["', jsonName, '"])']; } + return ["decode_", name, '(m["', jsonName, '"])']; } ); @@ -626,6 +637,7 @@ export class ElixirRenderer extends ConvenienceRenderer { if (arrayElement instanceof ArrayType) { return expression; } + if (arrayElement.isPrimitive()) { return expression; } else if (arrayElement instanceof MapType) { @@ -689,6 +701,7 @@ export class ElixirRenderer extends ConvenienceRenderer { "(value)} end)" ]; } + return [expression]; } }, @@ -721,12 +734,13 @@ export class ElixirRenderer extends ConvenienceRenderer { return ["struct.", e, " && encode_", e, "(struct.", e, ")"]; } + return ["encode_", e, "(struct.", e, ")"]; } ); } - private emitBlock(source: Sourcelike, emit: () => void) { + private emitBlock(source: Sourcelike, emit: () => void): void { this.emitLine(source); this.indent(emit); this.emitLine("end"); @@ -740,7 +754,7 @@ export class ElixirRenderer extends ConvenienceRenderer { }); } - private emitModule(c: ClassType, moduleName: Name) { + private emitModule(c: ClassType, moduleName: Name): void { this.emitBlock(["defmodule ", this.nameWithNamespace(moduleName), " do"], () => { const structDescription = this.descriptionForType(c) ?? []; const attributeDescriptions: Sourcelike[][] = []; @@ -754,6 +768,7 @@ export class ElixirRenderer extends ConvenienceRenderer { this.emitDescription([...structDescription, ...attributeDescriptions]); this.ensureBlankLine(); } + const requiredAttributes: Sourcelike[] = []; this.forEachClassProperty(c, "none", (name, _jsonName, p) => { if (!p.isOptional) { @@ -767,6 +782,7 @@ export class ElixirRenderer extends ConvenienceRenderer { if (requiredAttributes.length) { this.emitLine(["@enforce_keys [", requiredAttributes, "]"]); } + const attributeNames: Sourcelike[] = []; this.forEachClassProperty(c, "none", (name, _jsonName, _p) => { if (attributeNames.length === 0) { @@ -794,6 +810,7 @@ export class ElixirRenderer extends ConvenienceRenderer { if (this._options.justTypes) { return; } + this.forEachClassProperty(c, "none", (name, _jsonName, p) => { if (p.type.kind === "union") { const unionTypes = [...p.type.getChildren()]; @@ -925,7 +942,7 @@ export class ElixirRenderer extends ConvenienceRenderer { return true; } - private emitEnum(e: EnumType, enumName: Name) { + private emitEnum(e: EnumType, enumName: Name): void { this.emitBlock(["defmodule ", this.nameWithNamespace(enumName), " do"], () => { this.emitDescription(this.descriptionForType(e)); this.emitLine("@valid_enum_members ["); @@ -984,11 +1001,11 @@ end`); }); } - private emitUnion(_u: UnionType, _unionName: Name) { + private emitUnion(_u: UnionType, _unionName: Name): void { return; } - protected emitSourceStructure() { + protected emitSourceStructure(): void { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else if (!this._options.justTypes) { From 4620ba55663f423307f9820198e45eb776ca16e4 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 09:16:05 -0700 Subject: [PATCH 32/80] make ref.pushElement public --- packages/quicktype-core/src/input/JSONSchemaInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index a88e78157..ccd68d231 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -201,7 +201,7 @@ export class Ref { return this.path.length === 1 && this.path[0].kind === PathElementKind.Root; } - private pushElement(pe: PathElement): Ref { + public pushElement(pe: PathElement): Ref { const newPath = Array.from(this.path); newPath.push(pe); return new Ref(this.addressURI, newPath); From 4fe1649b5022aa23530b767fefeda9697beb85aa Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 09:42:16 -0700 Subject: [PATCH 33/80] fix misc --- packages/quicktype-core/src/Naming.ts | 6 ++++-- packages/quicktype-core/src/input/Inputs.ts | 2 +- packages/quicktype-core/src/input/JSONSchemaInput.ts | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/quicktype-core/src/Naming.ts b/packages/quicktype-core/src/Naming.ts index 94c6ca452..6b2b2b825 100644 --- a/packages/quicktype-core/src/Naming.ts +++ b/packages/quicktype-core/src/Naming.ts @@ -403,7 +403,9 @@ export function assignNames(rootNamespaces: Iterable): ReadonlyMap ctx.areForbiddensFullyNamed(ns)); - const readyNamespace = iterableFind(unfinishedNamespaces, ns => iterableSome(ns.members, ctx.isReadyToBeNamed)); + const readyNamespace = iterableFind(unfinishedNamespaces, ns => + iterableSome(ns.members, member => ctx.isReadyToBeNamed(member)) + ); if (readyNamespace === undefined) { // FIXME: Check for cycles? @@ -418,7 +420,7 @@ export function assignNames(rootNamespaces: Iterable): ReadonlyMap ctx.isReadyToBeNamed(member)); const minOrderName = iterableMinBy(allReadyNames, n => n.order); if (minOrderName === undefined) break; const minOrder = minOrderName.order; diff --git a/packages/quicktype-core/src/input/Inputs.ts b/packages/quicktype-core/src/input/Inputs.ts index be10e48d2..96d78756a 100644 --- a/packages/quicktype-core/src/input/Inputs.ts +++ b/packages/quicktype-core/src/input/Inputs.ts @@ -169,7 +169,7 @@ export class InputData { // eslint-disable-next-line @typescript-eslint/no-explicit-any private _inputs: Set> = new Set(); - protected addInput(input: Input): void { + public addInput(input: Input): void { this._inputs = this._inputs.add(input); } diff --git a/packages/quicktype-core/src/input/JSONSchemaInput.ts b/packages/quicktype-core/src/input/JSONSchemaInput.ts index ccd68d231..e000f7f40 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -201,14 +201,15 @@ export class Ref { return this.path.length === 1 && this.path[0].kind === PathElementKind.Root; } - public pushElement(pe: PathElement): Ref { + private pushElement(pe: PathElement): Ref { const newPath = Array.from(this.path); newPath.push(pe); return new Ref(this.addressURI, newPath); } public push(...keys: string[]): Ref { - let ref: Ref = { ...this }; + // eslint-disable-next-line @typescript-eslint/no-this-alias + let ref: Ref = this; for (const key of keys) { ref = ref.pushElement({ kind: PathElementKind.KeyOrIndex, key }); } From eed53c66164bd32724f614c7db64516d5b19877c Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 09:52:09 -0700 Subject: [PATCH 34/80] fix accidental public in CSharp raw text get --- packages/quicktype-core/src/language/CSharp.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/quicktype-core/src/language/CSharp.ts b/packages/quicktype-core/src/language/CSharp.ts index 159dab900..331345d66 100644 --- a/packages/quicktype-core/src/language/CSharp.ts +++ b/packages/quicktype-core/src/language/CSharp.ts @@ -2433,19 +2433,19 @@ internal class IsoDateTimeOffsetConverter : JsonConverter public DateTimeStyles DateTimeStyles { -public get => _dateTimeStyles; + get => _dateTimeStyles; set => _dateTimeStyles = value; } public string? DateTimeFormat { -public get => _dateTimeFormat ?? string.Empty; + get => _dateTimeFormat ?? string.Empty; set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; } public CultureInfo Culture { -public get => _culture ?? CultureInfo.CurrentCulture; + get => _culture ?? CultureInfo.CurrentCulture; set => _culture = value; } From 8e6fc4f9aee06f362ac75e4b4a37894fa169f923 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Mon, 29 Apr 2024 20:37:58 -0700 Subject: [PATCH 35/80] fix new lint errors --- packages/quicktype-core/src/input/io/NodeIO.ts | 2 ++ packages/quicktype-core/src/language/TypeScriptFlow.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/quicktype-core/src/input/io/NodeIO.ts b/packages/quicktype-core/src/input/io/NodeIO.ts index d23363b65..f8cf94b44 100644 --- a/packages/quicktype-core/src/input/io/NodeIO.ts +++ b/packages/quicktype-core/src/input/io/NodeIO.ts @@ -12,6 +12,8 @@ import { messageError, panic } from "../../index"; import { getStream } from "./get-stream"; // Only use cross-fetch in CI +// FIXME: type global +// eslint-disable-next-line @typescript-eslint/no-explicit-any const fetch = process.env.CI ? _fetch : (global as any).fetch ?? _fetch; interface HttpHeaders { diff --git a/packages/quicktype-core/src/language/TypeScriptFlow.ts b/packages/quicktype-core/src/language/TypeScriptFlow.ts index 74b527568..202b95b4e 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow.ts @@ -212,6 +212,7 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { if (!t.isPrimitive()) { return; } + this.ensureBlankLine(); this.emitDescription(this.descriptionForType(t)); this.emitLine("type ", name, " = ", this.sourceFor(t).source, ";"); From 4e2d89dab0d1b3f134f3e010522c6d81f69916ff Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Fri, 12 Apr 2024 23:44:00 -0700 Subject: [PATCH 36/80] rename ruby to Ruby --- packages/quicktype-core/src/index.ts | 2 +- packages/quicktype-core/src/language/All.ts | 2 +- packages/quicktype-core/src/language/{ruby => Ruby}/index.ts | 0 packages/quicktype-core/src/language/{ruby => Ruby}/keywords.ts | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename packages/quicktype-core/src/language/{ruby => Ruby}/index.ts (100%) rename packages/quicktype-core/src/language/{ruby => Ruby}/keywords.ts (100%) diff --git a/packages/quicktype-core/src/index.ts b/packages/quicktype-core/src/index.ts index fa1ea78be..0fb6d92a6 100644 --- a/packages/quicktype-core/src/index.ts +++ b/packages/quicktype-core/src/index.ts @@ -111,7 +111,7 @@ export { SmithyTargetLanguage, Smithy4sRenderer, SmithyOptions } from "./languag export { ElmTargetLanguage, ElmRenderer, elmOptions } from "./language/Elm"; export { JSONSchemaTargetLanguage, JSONSchemaRenderer } from "./language/JSONSchema"; export { RustTargetLanguage, RustRenderer, rustOptions } from "./language/Rust"; -export { RubyTargetLanguage, RubyRenderer, rubyOptions } from "./language/ruby"; +export { RubyTargetLanguage, RubyRenderer, rubyOptions } from "./language/Ruby"; export { CrystalTargetLanguage, CrystalRenderer } from "./language/Crystal"; export { HaskellTargetLanguage, HaskellRenderer, haskellOptions } from "./language/Haskell"; export { DartTargetLanguage, DartRenderer, dartOptions } from "./language/Dart"; diff --git a/packages/quicktype-core/src/language/All.ts b/packages/quicktype-core/src/language/All.ts index 297af4d1c..673405d22 100644 --- a/packages/quicktype-core/src/language/All.ts +++ b/packages/quicktype-core/src/language/All.ts @@ -21,7 +21,7 @@ import { ObjectiveCTargetLanguage } from "./Objective-C"; import { PhpTargetLanguage } from "./Php"; import { PikeTargetLanguage } from "./Pike"; import { PythonTargetLanguage } from "./Python"; -import { RubyTargetLanguage } from "./ruby"; +import { RubyTargetLanguage } from "./Ruby"; import { RustTargetLanguage } from "./Rust"; import { Scala3TargetLanguage } from "./Scala3"; import { SmithyTargetLanguage } from "./Smithy4s"; diff --git a/packages/quicktype-core/src/language/ruby/index.ts b/packages/quicktype-core/src/language/Ruby/index.ts similarity index 100% rename from packages/quicktype-core/src/language/ruby/index.ts rename to packages/quicktype-core/src/language/Ruby/index.ts diff --git a/packages/quicktype-core/src/language/ruby/keywords.ts b/packages/quicktype-core/src/language/Ruby/keywords.ts similarity index 100% rename from packages/quicktype-core/src/language/ruby/keywords.ts rename to packages/quicktype-core/src/language/Ruby/keywords.ts From 4147039349dad468c517b4c1c608dc10c478c261 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 00:18:13 -0700 Subject: [PATCH 37/80] move TypeScriptZod to own dir --- .../TypeScriptZodRenderer.ts} | 66 ++++--------------- .../src/language/TypeScriptZod/index.ts | 2 + .../src/language/TypeScriptZod/language.ts | 45 +++++++++++++ 3 files changed, 60 insertions(+), 53 deletions(-) rename packages/quicktype-core/src/language/{TypeScriptZod.ts => TypeScriptZod/TypeScriptZodRenderer.ts} (85%) create mode 100644 packages/quicktype-core/src/language/TypeScriptZod/index.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptZod/language.ts diff --git a/packages/quicktype-core/src/language/TypeScriptZod.ts b/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts similarity index 85% rename from packages/quicktype-core/src/language/TypeScriptZod.ts rename to packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts index ada7494a9..6b06e1a45 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts @@ -1,11 +1,11 @@ import { arrayIntercalate } from "collection-utils"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { AcronymStyleOptions, acronymStyle } from "../support/Acronyms"; +import { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike } from "../../Source"; +import { AcronymStyleOptions, acronymStyle } from "../../support/Acronyms"; import { allLowerWordStyle, capitalize, @@ -15,62 +15,22 @@ import { splitIntoWords, stringEscape, utf16StringEscape -} from "../support/Strings"; -import { panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; +} from "../../support/Strings"; +import { panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, ClassType, type EnumType, ObjectType, - type PrimitiveStringTypeKind, SetOperationType, - type TransformedStringTypeKind, type Type -} from "../Type"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType } from "../TypeUtils"; +} from "../../Type"; +import { matchType } from "../../TypeUtils"; +import { legalizeName } from "../JavaScript"; -import { legalizeName } from "./JavaScript"; - -export const typeScriptZodOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false) -}; - -export class TypeScriptZodTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { - return []; - } - - public constructor( - displayName: string = "TypeScript Zod", - names: string[] = ["typescript-zod"], - extension: string = "ts" - ) { - super(displayName, names, extension); - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - const dateTimeType = "date-time"; - mapping.set("date-time", dateTimeType); - return mapping; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): TypeScriptZodRenderer { - return new TypeScriptZodRenderer( - this, - renderContext, - getOptionValues(typeScriptZodOptions, untypedOptionValues) - ); - } -} +import { type typeScriptZodOptions } from "./language"; export class TypeScriptZodRenderer extends ConvenienceRenderer { public constructor( diff --git a/packages/quicktype-core/src/language/TypeScriptZod/index.ts b/packages/quicktype-core/src/language/TypeScriptZod/index.ts new file mode 100644 index 000000000..657c2f91c --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptZod/index.ts @@ -0,0 +1,2 @@ +export { TypeScriptZodTargetLanguage, typeScriptZodOptions } from "./language"; +export { TypeScriptZodRenderer } from "./TypeScriptZodRenderer"; diff --git a/packages/quicktype-core/src/language/TypeScriptZod/language.ts b/packages/quicktype-core/src/language/TypeScriptZod/language.ts new file mode 100644 index 000000000..a22f1298a --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptZod/language.ts @@ -0,0 +1,45 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, type Option, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { TypeScriptZodRenderer } from "./TypeScriptZodRenderer"; + +export const typeScriptZodOptions = { + justSchema: new BooleanOption("just-schema", "Schema only", false) +}; + +export class TypeScriptZodTargetLanguage extends TargetLanguage { + protected getOptions(): Array> { + return []; + } + + public constructor( + displayName: string = "TypeScript Zod", + names: string[] = ["typescript-zod"], + extension: string = "ts" + ) { + super(displayName, names, extension); + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + const dateTimeType = "date-time"; + mapping.set("date-time", dateTimeType); + return mapping; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): TypeScriptZodRenderer { + return new TypeScriptZodRenderer( + this, + renderContext, + getOptionValues(typeScriptZodOptions, untypedOptionValues) + ); + } +} From e8da6005d5d49b94710976bd334efd22866c5cbc Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 00:59:44 -0700 Subject: [PATCH 38/80] move TypeScriptFlow to own dir --- .../src/language/TypeScriptFlow.ts | 406 ------------------ .../language/TypeScriptFlow/FlowRenderer.ts | 47 ++ .../TypeScriptFlowBaseRenderer.ts | 190 ++++++++ .../TypeScriptFlow/TypeScriptRenderer.ts | 88 ++++ .../src/language/TypeScriptFlow/index.ts | 3 + .../src/language/TypeScriptFlow/language.ts | 68 +++ .../src/language/TypeScriptFlow/utils.ts | 29 ++ 7 files changed, 425 insertions(+), 406 deletions(-) delete mode 100644 packages/quicktype-core/src/language/TypeScriptFlow.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptFlow/index.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptFlow/language.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptFlow/utils.ts diff --git a/packages/quicktype-core/src/language/TypeScriptFlow.ts b/packages/quicktype-core/src/language/TypeScriptFlow.ts deleted file mode 100644 index 202b95b4e..000000000 --- a/packages/quicktype-core/src/language/TypeScriptFlow.ts +++ /dev/null @@ -1,406 +0,0 @@ -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type MultiWord, type Sourcelike, modifySource, multiWord, parenIfNeeded, singleWord } from "../Source"; -import { camelCase, utf16StringEscape } from "../support/Strings"; -import { defined, panic } from "../support/Support"; -import { type TargetLanguage } from "../TargetLanguage"; -import { ArrayType, type ClassType, EnumType, type Type, UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { isNamedType, matchType, nullableFromUnion } from "../TypeUtils"; - -import { - JavaScriptRenderer, - JavaScriptTargetLanguage, - type JavaScriptTypeAnnotations, - javaScriptOptions, - legalizeName -} from "./JavaScript"; -import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; - -export const tsFlowOptions = Object.assign({}, javaScriptOptions, { - justTypes: new BooleanOption("just-types", "Interfaces only", false), - nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be JavaScripty", false), - declareUnions: new BooleanOption("explicit-unions", "Explicitly name unions", false), - preferUnions: new BooleanOption("prefer-unions", "Use union type instead of enum", false), - preferTypes: new BooleanOption("prefer-types", "Use types instead of interfaces", false), - preferConstValues: new BooleanOption( - "prefer-const-values", - "Use string instead of enum for string enums with single value", - false - ), - readonly: new BooleanOption("readonly", "Use readonly type members", false) -}); - -const tsFlowTypeAnnotations = { - any: ": any", - anyArray: ": any[]", - anyMap: ": { [k: string]: any }", - string: ": string", - stringArray: ": string[]", - boolean: ": boolean" -}; - -export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetLanguage { - protected getOptions(): Array> { - return [ - tsFlowOptions.justTypes, - tsFlowOptions.nicePropertyNames, - tsFlowOptions.declareUnions, - tsFlowOptions.runtimeTypecheck, - tsFlowOptions.runtimeTypecheckIgnoreUnknownProperties, - tsFlowOptions.acronymStyle, - tsFlowOptions.converters, - tsFlowOptions.rawType, - tsFlowOptions.preferUnions, - tsFlowOptions.preferTypes, - tsFlowOptions.preferConstValues, - tsFlowOptions.readonly - ]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - protected abstract makeRenderer( - renderContext: RenderContext, - untypedOptionValues: FixMeOptionsType - ): JavaScriptRenderer; -} - -export class TypeScriptTargetLanguage extends TypeScriptFlowBaseTargetLanguage { - public constructor() { - super("TypeScript", ["typescript", "ts", "tsx"], "ts"); - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): TypeScriptRenderer { - return new TypeScriptRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); - } -} - -function quotePropertyName(original: string): string { - const escaped = utf16StringEscape(original); - const quoted = `"${escaped}"`; - - if (original.length === 0) { - return quoted; - } else if (!isES3IdentifierStart(original.codePointAt(0) as number)) { - return quoted; - } else if (escaped !== original) { - return quoted; - } else if (legalizeName(original) !== original) { - return quoted; - } else { - return original; - } -} - -export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - protected readonly _tsFlowOptions: OptionValues - ) { - super(targetLanguage, renderContext, _tsFlowOptions); - } - - protected namerForObjectProperty(): Namer { - if (this._tsFlowOptions.nicePropertyNames) { - return funPrefixNamer("properties", s => this.nameStyle(s, false)); - } else { - return super.namerForObjectProperty(); - } - } - - protected sourceFor(t: Type): MultiWord { - if (this._tsFlowOptions.preferConstValues && t.kind === "enum" && t instanceof EnumType && t.cases.size === 1) { - const item = t.cases.values().next().value; - return singleWord(`"${utf16StringEscape(item)}"`); - } - - if (["class", "object", "enum"].includes(t.kind)) { - return singleWord(this.nameForNamedType(t)); - } - - return matchType( - t, - _anyType => singleWord("any"), - _nullType => singleWord("null"), - _boolType => singleWord("boolean"), - _integerType => singleWord("number"), - _doubleType => singleWord("number"), - _stringType => singleWord("string"), - arrayType => { - const itemType = this.sourceFor(arrayType.items); - if ( - (arrayType.items instanceof UnionType && !this._tsFlowOptions.declareUnions) || - arrayType.items instanceof ArrayType - ) { - return singleWord(["Array<", itemType.source, ">"]); - } else { - return singleWord([parenIfNeeded(itemType), "[]"]); - } - }, - _classType => panic("We handled this above"), - mapType => singleWord(["{ [key: string]: ", this.sourceFor(mapType.values).source, " }"]), - _enumType => panic("We handled this above"), - unionType => { - if (!this._tsFlowOptions.declareUnions || nullableFromUnion(unionType) !== null) { - const children = Array.from(unionType.getChildren()).map(c => parenIfNeeded(this.sourceFor(c))); - return multiWord(" | ", ...children); - } else { - return singleWord(this.nameForNamedType(unionType)); - } - }, - transformedStringType => { - if (transformedStringType.kind === "date-time") { - return singleWord("Date"); - } - - return singleWord("string"); - } - ); - } - - protected abstract emitEnum(e: EnumType, enumName: Name): void; - - protected abstract emitClassBlock(c: ClassType, className: Name): void; - - protected emitClassBlockBody(c: ClassType): void { - this.emitPropertyTable(c, (name, _jsonName, p) => { - const t = p.type; - - let propertyName: Sourcelike = name; - propertyName = modifySource(quotePropertyName, name); - - if (this._tsFlowOptions.readonly) { - propertyName = modifySource(_propertyName => "readonly " + _propertyName, propertyName); - } - - return [ - [propertyName, p.isOptional ? "?" : "", ": "], - [this.sourceFor(t).source, ";"] - ]; - }); - - const additionalProperties = c.getAdditionalProperties(); - if (additionalProperties) { - this.emitTable([["[property: string]", ": ", this.sourceFor(additionalProperties).source, ";"]]); - } - } - - private emitClass(c: ClassType, className: Name): void { - this.emitDescription(this.descriptionForType(c)); - this.emitClassBlock(c, className); - } - - protected emitUnion(u: UnionType, unionName: Name): void { - if (!this._tsFlowOptions.declareUnions) { - return; - } - - this.emitDescription(this.descriptionForType(u)); - - const children = multiWord(" | ", ...Array.from(u.getChildren()).map(c => parenIfNeeded(this.sourceFor(c)))); - this.emitLine("export type ", unionName, " = ", children.source, ";"); - } - - protected emitTypes(): void { - // emit primitive top levels - this.forEachTopLevel("none", (t, name) => { - if (!t.isPrimitive()) { - return; - } - - this.ensureBlankLine(); - this.emitDescription(this.descriptionForType(t)); - this.emitLine("type ", name, " = ", this.sourceFor(t).source, ";"); - }); - - this.forEachNamedType( - "leading-and-interposing", - (c: ClassType, n: Name) => this.emitClass(c, n), - (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n) - ); - } - - protected emitUsageComments(): void { - if (this._tsFlowOptions.justTypes) return; - super.emitUsageComments(); - } - - protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { - const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; - return ["function to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; - } - - protected serializerFunctionLine(t: Type, name: Name): Sourcelike { - const camelCaseName = modifySource(camelCase, name); - const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; - return ["function ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; - } - - protected get moduleLine(): string | undefined { - return undefined; - } - - protected get castFunctionLines(): [string, string] { - return ["function cast(val: any, typ: any): T", "function uncast(val: T, typ: any): any"]; - } - - protected get typeAnnotations(): JavaScriptTypeAnnotations { - throw new Error("not implemented"); - } - - protected emitConvertModule(): void { - if (this._tsFlowOptions.justTypes) return; - super.emitConvertModule(); - } - - protected emitConvertModuleHelpers(): void { - if (this._tsFlowOptions.justTypes) return; - super.emitConvertModuleHelpers(); - } - - protected emitModuleExports(): void { - if (this._tsFlowOptions.justTypes) { - return; - } else { - super.emitModuleExports(); - } - } -} - -export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { - protected forbiddenNamesForGlobalNamespace(): string[] { - return ["Array", "Date"]; - } - - protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { - const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; - return ["public static to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; - } - - protected serializerFunctionLine(t: Type, name: Name): Sourcelike { - const camelCaseName = modifySource(camelCase, name); - const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; - return ["public static ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; - } - - protected get moduleLine(): string | undefined { - return "export class Convert"; - } - - protected get typeAnnotations(): JavaScriptTypeAnnotations { - return Object.assign({ never: ": never" }, tsFlowTypeAnnotations); - } - - protected emitModuleExports(): void { - return; - } - - protected emitUsageImportComment(): void { - const topLevelNames: Sourcelike[] = []; - this.forEachTopLevel( - "none", - (_t, name) => { - topLevelNames.push(", ", name); - }, - isNamedType - ); - this.emitLine("// import { Convert", topLevelNames, ' } from "./file";'); - } - - protected emitEnum(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - - // enums with only one value are emitted as constants - if (this._tsFlowOptions.preferConstValues && e.cases.size === 1) return; - - if (this._tsFlowOptions.preferUnions) { - let items = ""; - e.cases.forEach(item => { - if (items === "") { - items += `"${utf16StringEscape(item)}"`; - return; - } - - items += ` | "${utf16StringEscape(item)}"`; - }); - this.emitLine("export type ", enumName, " = ", items, ";"); - } else { - this.emitBlock(["export enum ", enumName, " "], "", () => { - this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine(name, ` = "${utf16StringEscape(jsonName)}",`); - }); - }); - } - } - - protected emitClassBlock(c: ClassType, className: Name): void { - this.emitBlock( - this._tsFlowOptions.preferTypes - ? ["export type ", className, " = "] - : ["export interface ", className, " "], - "", - () => { - this.emitClassBlockBody(c); - } - ); - } - - protected emitSourceStructure() { - super.emitSourceStructure(); - } -} - -export class FlowTargetLanguage extends TypeScriptFlowBaseTargetLanguage { - public constructor() { - super("Flow", ["flow"], "js"); - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): FlowRenderer { - return new FlowRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); - } -} - -export class FlowRenderer extends TypeScriptFlowBaseRenderer { - protected forbiddenNamesForGlobalNamespace(): string[] { - return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; - } - - protected get typeAnnotations(): JavaScriptTypeAnnotations { - return Object.assign({ never: "" }, tsFlowTypeAnnotations); - } - - protected emitEnum(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - const lines: string[][] = []; - this.forEachEnumCase(e, "none", (_, jsonName) => { - const maybeOr = lines.length === 0 ? " " : "| "; - lines.push([maybeOr, '"', utf16StringEscape(jsonName), '"']); - }); - defined(lines[lines.length - 1]).push(";"); - - this.emitLine("export type ", enumName, " ="); - this.indent(() => { - for (const line of lines) { - this.emitLine(line); - } - }); - } - - protected emitClassBlock(c: ClassType, className: Name): void { - this.emitBlock(["export type ", className, " = "], ";", () => { - this.emitClassBlockBody(c); - }); - } - - protected emitSourceStructure(): void { - this.emitLine("// @flow"); - this.ensureBlankLine(); - super.emitSourceStructure(); - } -} diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts new file mode 100644 index 000000000..eb4695583 --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts @@ -0,0 +1,47 @@ +import { type Name } from "../../Naming"; +import { utf16StringEscape } from "../../support/Strings"; +import { defined } from "../../support/Support"; +import { type ClassType, type EnumType } from "../../Type"; +import { type JavaScriptTypeAnnotations } from "../JavaScript"; + +import { TypeScriptFlowBaseRenderer } from "./TypeScriptFlowBaseRenderer"; +import { tsFlowTypeAnnotations } from "./utils"; + +export class FlowRenderer extends TypeScriptFlowBaseRenderer { + protected forbiddenNamesForGlobalNamespace(): string[] { + return ["Class", "Date", "Object", "String", "Array", "JSON", "Error"]; + } + + protected get typeAnnotations(): JavaScriptTypeAnnotations { + return Object.assign({ never: "" }, tsFlowTypeAnnotations); + } + + protected emitEnum(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + const lines: string[][] = []; + this.forEachEnumCase(e, "none", (_, jsonName) => { + const maybeOr = lines.length === 0 ? " " : "| "; + lines.push([maybeOr, '"', utf16StringEscape(jsonName), '"']); + }); + defined(lines[lines.length - 1]).push(";"); + + this.emitLine("export type ", enumName, " ="); + this.indent(() => { + for (const line of lines) { + this.emitLine(line); + } + }); + } + + protected emitClassBlock(c: ClassType, className: Name): void { + this.emitBlock(["export type ", className, " = "], ";", () => { + this.emitClassBlockBody(c); + }); + } + + protected emitSourceStructure(): void { + this.emitLine("// @flow"); + this.ensureBlankLine(); + super.emitSourceStructure(); + } +} diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts new file mode 100644 index 000000000..3cc9b09bf --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts @@ -0,0 +1,190 @@ +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type MultiWord, type Sourcelike, modifySource, multiWord, parenIfNeeded, singleWord } from "../../Source"; +import { camelCase, utf16StringEscape } from "../../support/Strings"; +import { panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, type ClassType, EnumType, type Type, UnionType } from "../../Type"; +import { matchType, nullableFromUnion } from "../../TypeUtils"; +import { JavaScriptRenderer, type JavaScriptTypeAnnotations } from "../JavaScript"; + +import { type tsFlowOptions } from "./language"; +import { quotePropertyName } from "./utils"; + +export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + protected readonly _tsFlowOptions: OptionValues + ) { + super(targetLanguage, renderContext, _tsFlowOptions); + } + + protected namerForObjectProperty(): Namer { + if (this._tsFlowOptions.nicePropertyNames) { + return funPrefixNamer("properties", s => this.nameStyle(s, false)); + } else { + return super.namerForObjectProperty(); + } + } + + protected sourceFor(t: Type): MultiWord { + if (this._tsFlowOptions.preferConstValues && t.kind === "enum" && t instanceof EnumType && t.cases.size === 1) { + const item = t.cases.values().next().value; + return singleWord(`"${utf16StringEscape(item)}"`); + } + + if (["class", "object", "enum"].includes(t.kind)) { + return singleWord(this.nameForNamedType(t)); + } + + return matchType( + t, + _anyType => singleWord("any"), + _nullType => singleWord("null"), + _boolType => singleWord("boolean"), + _integerType => singleWord("number"), + _doubleType => singleWord("number"), + _stringType => singleWord("string"), + arrayType => { + const itemType = this.sourceFor(arrayType.items); + if ( + (arrayType.items instanceof UnionType && !this._tsFlowOptions.declareUnions) || + arrayType.items instanceof ArrayType + ) { + return singleWord(["Array<", itemType.source, ">"]); + } else { + return singleWord([parenIfNeeded(itemType), "[]"]); + } + }, + _classType => panic("We handled this above"), + mapType => singleWord(["{ [key: string]: ", this.sourceFor(mapType.values).source, " }"]), + _enumType => panic("We handled this above"), + unionType => { + if (!this._tsFlowOptions.declareUnions || nullableFromUnion(unionType) !== null) { + const children = Array.from(unionType.getChildren()).map(c => parenIfNeeded(this.sourceFor(c))); + return multiWord(" | ", ...children); + } else { + return singleWord(this.nameForNamedType(unionType)); + } + }, + transformedStringType => { + if (transformedStringType.kind === "date-time") { + return singleWord("Date"); + } + + return singleWord("string"); + } + ); + } + + protected abstract emitEnum(e: EnumType, enumName: Name): void; + + protected abstract emitClassBlock(c: ClassType, className: Name): void; + + protected emitClassBlockBody(c: ClassType): void { + this.emitPropertyTable(c, (name, _jsonName, p) => { + const t = p.type; + + let propertyName: Sourcelike = name; + propertyName = modifySource(quotePropertyName, name); + + if (this._tsFlowOptions.readonly) { + propertyName = modifySource(_propertyName => "readonly " + _propertyName, propertyName); + } + + return [ + [propertyName, p.isOptional ? "?" : "", ": "], + [this.sourceFor(t).source, ";"] + ]; + }); + + const additionalProperties = c.getAdditionalProperties(); + if (additionalProperties) { + this.emitTable([["[property: string]", ": ", this.sourceFor(additionalProperties).source, ";"]]); + } + } + + private emitClass(c: ClassType, className: Name): void { + this.emitDescription(this.descriptionForType(c)); + this.emitClassBlock(c, className); + } + + protected emitUnion(u: UnionType, unionName: Name): void { + if (!this._tsFlowOptions.declareUnions) { + return; + } + + this.emitDescription(this.descriptionForType(u)); + + const children = multiWord(" | ", ...Array.from(u.getChildren()).map(c => parenIfNeeded(this.sourceFor(c)))); + this.emitLine("export type ", unionName, " = ", children.source, ";"); + } + + protected emitTypes(): void { + // emit primitive top levels + this.forEachTopLevel("none", (t, name) => { + if (!t.isPrimitive()) { + return; + } + + this.ensureBlankLine(); + this.emitDescription(this.descriptionForType(t)); + this.emitLine("type ", name, " = ", this.sourceFor(t).source, ";"); + }); + + this.forEachNamedType( + "leading-and-interposing", + (c: ClassType, n: Name) => this.emitClass(c, n), + (e, n) => this.emitEnum(e, n), + (u, n) => this.emitUnion(u, n) + ); + } + + protected emitUsageComments(): void { + if (this._tsFlowOptions.justTypes) return; + super.emitUsageComments(); + } + + protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { + const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; + return ["function to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; + } + + protected serializerFunctionLine(t: Type, name: Name): Sourcelike { + const camelCaseName = modifySource(camelCase, name); + const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; + return ["function ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; + } + + protected get moduleLine(): string | undefined { + return undefined; + } + + protected get castFunctionLines(): [string, string] { + return ["function cast(val: any, typ: any): T", "function uncast(val: T, typ: any): any"]; + } + + protected get typeAnnotations(): JavaScriptTypeAnnotations { + throw new Error("not implemented"); + } + + protected emitConvertModule(): void { + if (this._tsFlowOptions.justTypes) return; + super.emitConvertModule(); + } + + protected emitConvertModuleHelpers(): void { + if (this._tsFlowOptions.justTypes) return; + super.emitConvertModuleHelpers(); + } + + protected emitModuleExports(): void { + if (this._tsFlowOptions.justTypes) { + return; + } else { + super.emitModuleExports(); + } + } +} diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts new file mode 100644 index 000000000..74edd55ed --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts @@ -0,0 +1,88 @@ +import { type Name } from "../../Naming"; +import { type Sourcelike, modifySource } from "../../Source"; +import { camelCase, utf16StringEscape } from "../../support/Strings"; +import { type ClassType, type EnumType, type Type } from "../../Type"; +import { isNamedType } from "../../TypeUtils"; +import { type JavaScriptTypeAnnotations } from "../JavaScript"; + +import { TypeScriptFlowBaseRenderer } from "./TypeScriptFlowBaseRenderer"; +import { tsFlowTypeAnnotations } from "./utils"; + +export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { + protected forbiddenNamesForGlobalNamespace(): string[] { + return ["Array", "Date"]; + } + + protected deserializerFunctionLine(t: Type, name: Name): Sourcelike { + const jsonType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; + return ["public static to", name, "(json: ", jsonType, "): ", this.sourceFor(t).source]; + } + + protected serializerFunctionLine(t: Type, name: Name): Sourcelike { + const camelCaseName = modifySource(camelCase, name); + const returnType = this._tsFlowOptions.rawType === "json" ? "string" : "any"; + return ["public static ", camelCaseName, "ToJson(value: ", this.sourceFor(t).source, "): ", returnType]; + } + + protected get moduleLine(): string | undefined { + return "export class Convert"; + } + + protected get typeAnnotations(): JavaScriptTypeAnnotations { + return Object.assign({ never: ": never" }, tsFlowTypeAnnotations); + } + + protected emitModuleExports(): void { + return; + } + + protected emitUsageImportComment(): void { + const topLevelNames: Sourcelike[] = []; + this.forEachTopLevel( + "none", + (_t, name) => { + topLevelNames.push(", ", name); + }, + isNamedType + ); + this.emitLine("// import { Convert", topLevelNames, ' } from "./file";'); + } + + protected emitEnum(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + + // enums with only one value are emitted as constants + if (this._tsFlowOptions.preferConstValues && e.cases.size === 1) return; + + if (this._tsFlowOptions.preferUnions) { + let items = ""; + e.cases.forEach(item => { + if (items === "") { + items += `"${utf16StringEscape(item)}"`; + return; + } + + items += ` | "${utf16StringEscape(item)}"`; + }); + this.emitLine("export type ", enumName, " = ", items, ";"); + } else { + this.emitBlock(["export enum ", enumName, " "], "", () => { + this.forEachEnumCase(e, "none", (name, jsonName) => { + this.emitLine(name, ` = "${utf16StringEscape(jsonName)}",`); + }); + }); + } + } + + protected emitClassBlock(c: ClassType, className: Name): void { + this.emitBlock( + this._tsFlowOptions.preferTypes + ? ["export type ", className, " = "] + : ["export interface ", className, " "], + "", + () => { + this.emitClassBlockBody(c); + } + ); + } +} diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/index.ts b/packages/quicktype-core/src/language/TypeScriptFlow/index.ts new file mode 100644 index 000000000..681acaa34 --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptFlow/index.ts @@ -0,0 +1,3 @@ +export { FlowRenderer } from "./FlowRenderer"; +export { TypeScriptRenderer } from "./TypeScriptRenderer"; +export { FlowTargetLanguage, TypeScriptTargetLanguage, tsFlowOptions } from "./language"; diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/language.ts b/packages/quicktype-core/src/language/TypeScriptFlow/language.ts new file mode 100644 index 000000000..8f8c37af5 --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptFlow/language.ts @@ -0,0 +1,68 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, type Option, getOptionValues } from "../../RendererOptions"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; +import { type JavaScriptRenderer, JavaScriptTargetLanguage, javaScriptOptions } from "../JavaScript"; + +import { FlowRenderer } from "./FlowRenderer"; +import { TypeScriptRenderer } from "./TypeScriptRenderer"; + +export const tsFlowOptions = Object.assign({}, javaScriptOptions, { + justTypes: new BooleanOption("just-types", "Interfaces only", false), + nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be JavaScripty", false), + declareUnions: new BooleanOption("explicit-unions", "Explicitly name unions", false), + preferUnions: new BooleanOption("prefer-unions", "Use union type instead of enum", false), + preferTypes: new BooleanOption("prefer-types", "Use types instead of interfaces", false), + preferConstValues: new BooleanOption( + "prefer-const-values", + "Use string instead of enum for string enums with single value", + false + ), + readonly: new BooleanOption("readonly", "Use readonly type members", false) +}); + +export abstract class TypeScriptFlowBaseTargetLanguage extends JavaScriptTargetLanguage { + protected getOptions(): Array> { + return [ + tsFlowOptions.justTypes, + tsFlowOptions.nicePropertyNames, + tsFlowOptions.declareUnions, + tsFlowOptions.runtimeTypecheck, + tsFlowOptions.runtimeTypecheckIgnoreUnknownProperties, + tsFlowOptions.acronymStyle, + tsFlowOptions.converters, + tsFlowOptions.rawType, + tsFlowOptions.preferUnions, + tsFlowOptions.preferTypes, + tsFlowOptions.preferConstValues, + tsFlowOptions.readonly + ]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + protected abstract makeRenderer( + renderContext: RenderContext, + untypedOptionValues: FixMeOptionsType + ): JavaScriptRenderer; +} + +export class TypeScriptTargetLanguage extends TypeScriptFlowBaseTargetLanguage { + public constructor() { + super("TypeScript", ["typescript", "ts", "tsx"], "ts"); + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): TypeScriptRenderer { + return new TypeScriptRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); + } +} +export class FlowTargetLanguage extends TypeScriptFlowBaseTargetLanguage { + public constructor() { + super("Flow", ["flow"], "js"); + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): FlowRenderer { + return new FlowRenderer(this, renderContext, getOptionValues(tsFlowOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts b/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts new file mode 100644 index 000000000..731f46cdd --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts @@ -0,0 +1,29 @@ +import { legalizeName } from "../../language/JavaScript"; +import { isES3IdentifierStart } from "../../language/JavaScriptUnicodeMaps"; +import { utf16StringEscape } from "../../support/Strings"; + +export const tsFlowTypeAnnotations = { + any: ": any", + anyArray: ": any[]", + anyMap: ": { [k: string]: any }", + string: ": string", + stringArray: ": string[]", + boolean: ": boolean" +}; + +export function quotePropertyName(original: string): string { + const escaped = utf16StringEscape(original); + const quoted = `"${escaped}"`; + + if (original.length === 0) { + return quoted; + } else if (!isES3IdentifierStart(original.codePointAt(0) as number)) { + return quoted; + } else if (escaped !== original) { + return quoted; + } else if (legalizeName(original) !== original) { + return quoted; + } else { + return original; + } +} From d1a5a5d8ae9e921036275b204574474438f4ee9c Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 01:06:22 -0700 Subject: [PATCH 39/80] move TypeScriptEffectSchema to own dir --- .../TypeScriptEffectSchemaRenderer.ts} | 57 +++++-------------- .../language/TypeScriptEffectSchema/index.ts | 0 .../TypeScriptEffectSchema/language.ts | 35 ++++++++++++ 3 files changed, 49 insertions(+), 43 deletions(-) rename packages/quicktype-core/src/language/{TypeScriptEffectSchema.ts => TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts} (82%) create mode 100644 packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts create mode 100644 packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts similarity index 82% rename from packages/quicktype-core/src/language/TypeScriptEffectSchema.ts rename to packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts index c3844d847..2c9946b4c 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts @@ -1,11 +1,11 @@ import { arrayIntercalate } from "collection-utils"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { AcronymStyleOptions, acronymStyle } from "../support/Acronyms"; +import { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike } from "../../Source"; +import { AcronymStyleOptions, acronymStyle } from "../../support/Acronyms"; import { allLowerWordStyle, capitalize, @@ -15,43 +15,14 @@ import { splitIntoWords, stringEscape, utf16StringEscape -} from "../support/Strings"; -import { panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, type ClassProperty, EnumType, MapType, type ObjectType, type Type } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType } from "../TypeUtils"; - -import { legalizeName } from "./JavaScript"; - -export const typeScriptEffectSchemaOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false) -}; - -export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { - return []; - } - - public constructor( - displayName: string = "TypeScript Effect Schema", - names: string[] = ["typescript-effect-schema"], - extension: string = "ts" - ) { - super(displayName, names, extension); - } - - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: FixMeOptionsType - ): TypeScriptEffectSchemaRenderer { - return new TypeScriptEffectSchemaRenderer( - this, - renderContext, - getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues) - ); - } -} +} from "../../support/Strings"; +import { panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, type ClassProperty, EnumType, MapType, type ObjectType, type Type } from "../../Type"; +import { matchType } from "../../TypeUtils"; +import { legalizeName } from "../JavaScript"; + +import { type typeScriptEffectSchemaOptions } from "./language"; export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { private emittedObjects = new Set(); diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts new file mode 100644 index 000000000..5e311edb0 --- /dev/null +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts @@ -0,0 +1,35 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, type Option, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { TypeScriptEffectSchemaRenderer } from "./TypeScriptEffectSchemaRenderer"; + +export const typeScriptEffectSchemaOptions = { + justSchema: new BooleanOption("just-schema", "Schema only", false) +}; + +export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage { + protected getOptions(): Array> { + return []; + } + + public constructor( + displayName: string = "TypeScript Effect Schema", + names: string[] = ["typescript-effect-schema"], + extension: string = "ts" + ) { + super(displayName, names, extension); + } + + protected makeRenderer( + renderContext: RenderContext, + untypedOptionValues: FixMeOptionsType + ): TypeScriptEffectSchemaRenderer { + return new TypeScriptEffectSchemaRenderer( + this, + renderContext, + getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues) + ); + } +} From fac0462c585b5c538c8fe329bcb7135b71749d53 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 08:46:03 -0700 Subject: [PATCH 40/80] make forbiddenNamesForGlobalNamespace return readonly --- packages/quicktype-core/src/ConvenienceRenderer.ts | 2 +- packages/quicktype-core/src/Naming.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/quicktype-core/src/ConvenienceRenderer.ts b/packages/quicktype-core/src/ConvenienceRenderer.ts index 2c9c6ff42..aef41b181 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -129,7 +129,7 @@ export abstract class ConvenienceRenderer extends Renderer { * that can conflict with that, such as reserved keywords or common type * names. */ - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return []; } diff --git a/packages/quicktype-core/src/Naming.ts b/packages/quicktype-core/src/Naming.ts index 6b2b2b825..cc98c50fc 100644 --- a/packages/quicktype-core/src/Naming.ts +++ b/packages/quicktype-core/src/Naming.ts @@ -319,7 +319,7 @@ export class DependencyName extends Name { } } -export function keywordNamespace(name: string, keywords: string[]): Namespace { +export function keywordNamespace(name: string, keywords: readonly string[]): Namespace { const ns = new Namespace(name, undefined, [], []); for (const kw of keywords) { ns.add(new FixedName(kw)); From bb5c2e8a34100d41b0434cbd0064716518bddd1b Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 08:47:54 -0700 Subject: [PATCH 41/80] fixup! move TypeScriptEffectSchema to own dir --- .../quicktype-core/src/language/TypeScriptEffectSchema/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts index e69de29bb..ea8cf8149 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts @@ -0,0 +1,2 @@ +export { TypeScriptEffectSchemaTargetLanguage, typeScriptEffectSchemaOptions } from "./language"; +export { TypeScriptEffectSchemaRenderer } from "./TypeScriptEffectSchemaRenderer"; From b7d5630a288de815a2c88c8b8b3080e07a44fb0e Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 08:48:04 -0700 Subject: [PATCH 42/80] move Swift to own dir --- .../{Swift.ts => Swift/SwiftRenderer.ts} | 843 ++++++------------ .../src/language/Swift/constants.ts | 101 +++ .../src/language/Swift/index.ts | 2 + .../src/language/Swift/language.ts | 128 +++ .../src/language/Swift/utils.ts | 84 ++ 5 files changed, 583 insertions(+), 575 deletions(-) rename packages/quicktype-core/src/language/{Swift.ts => Swift/SwiftRenderer.ts} (66%) create mode 100644 packages/quicktype-core/src/language/Swift/constants.ts create mode 100644 packages/quicktype-core/src/language/Swift/index.ts create mode 100644 packages/quicktype-core/src/language/Swift/language.ts create mode 100644 packages/quicktype-core/src/language/Swift/utils.ts diff --git a/packages/quicktype-core/src/language/Swift.ts b/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts similarity index 66% rename from packages/quicktype-core/src/language/Swift.ts rename to packages/quicktype-core/src/language/Swift/SwiftRenderer.ts index cb801de2b..89171de26 100644 --- a/packages/quicktype-core/src/language/Swift.ts +++ b/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts @@ -1,337 +1,30 @@ import { arrayIntercalate } from "collection-utils"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type DateTimeRecognizer, DefaultDateTimeRecognizer } from "../DateTime"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type ForEachPosition, type RenderContext } from "../Renderer"; -import { - BooleanOption, - EnumOption, - type Option, - type OptionValues, - StringOption, - getOptionValues -} from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; -import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; -import { - addPrefixIfNecessary, - allLowerWordStyle, - allUpperWordStyle, - camelCase, - combineWords, - escapeNonPrintableMapper, - firstUpperWordStyle, - intToHex, - isDigit, - isLetterOrUnderscore, - isNumeric, - isPrintable, - legalizeCharacters, - splitIntoWords, - utf32ConcatMap -} from "../support/Strings"; -import { assert, defined, panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../../Source"; +import { acronymStyle } from "../../support/Acronyms"; +import { camelCase, stringEscape } from "../../support/Strings"; +import { assert, defined, panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, type ClassType, EnumType, MapType, - type PrimitiveStringTypeKind, - type TransformedStringTypeKind, type Type, type TypeKind, type UnionType -} from "../Type"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -const MAX_SAMELINE_PROPERTIES = 4; - -export const swiftOptions = { - justTypes: new BooleanOption("just-types", "Plain types only", false), - convenienceInitializers: new BooleanOption("initializers", "Generate initializers and mutators", true), - explicitCodingKeys: new BooleanOption("coding-keys", "Explicit CodingKey values in Codable types", true), - codingKeysProtocol: new StringOption( - "coding-keys-protocol", - "CodingKeys implements protocols", - "protocol1, protocol2...", - "", - "secondary" - ), - alamofire: new BooleanOption("alamofire", "Alamofire extensions", false), - namedTypePrefix: new StringOption("type-prefix", "Prefix for type names", "PREFIX", "", "secondary"), - useClasses: new EnumOption("struct-or-class", "Structs or classes", [ - ["struct", false], - ["class", true] - ]), - mutableProperties: new BooleanOption("mutable-properties", "Use var instead of let for object properties", false), - acronymStyle: acronymOption(AcronymStyleOptions.Pascal), - dense: new EnumOption( - "density", - "Code density", - [ - ["dense", true], - ["normal", false] - ], - "dense", - "secondary" - ), - linux: new BooleanOption("support-linux", "Support Linux", false, "secondary"), - objcSupport: new BooleanOption( - "objective-c-support", - "Objects inherit from NSObject and @objcMembers is added to classes", - false - ), - optionalEnums: new BooleanOption("optional-enums", "If no matching case is found enum value is set to null", false), - swift5Support: new BooleanOption("swift-5-support", "Renders output in a Swift 5 compatible mode", false), - sendable: new BooleanOption("sendable", "Mark generated models as Sendable", false), - multiFileOutput: new BooleanOption( - "multi-file-output", - "Renders each top-level object in its own Swift file", - false - ), - accessLevel: new EnumOption( - "access-level", - "Access level", - [ - ["internal", "internal"], - ["public", "public"] - ], - "internal", - "secondary" - ), - protocol: new EnumOption( - "protocol", - "Make types implement protocol", - [ - ["none", { equatable: false, hashable: false }], - ["equatable", { equatable: true, hashable: false }], - ["hashable", { equatable: false, hashable: true }] - ], - "none", - "secondary" - ) -}; - -// These are all recognized by Swift as ISO8601 date-times: -// -// 2018-08-14T02:45:50+00:00 -// 2018-08-14T02:45:50+00 -// 2018-08-14T02:45:50+1 -// 2018-08-14T02:45:50+1111 -// 2018-08-14T02:45:50+1111:1:33 -// 2018-08-14T02:45:50-00 -// 2018-08-14T02:45:50z -// 2018-00008-1T002:45:3Z - -const swiftDateTimeRegex = /^\d+-\d+-\d+T\d+:\d+:\d+([zZ]|[+-]\d+(:\d+)?)$/; - -class SwiftDateTimeRecognizer extends DefaultDateTimeRecognizer { - public isDateTime(str: string): boolean { - return swiftDateTimeRegex.exec(str) !== null; - } -} - -export interface SwiftProperty { - jsonName: string; - name: Name; - parameter: ClassProperty; - position: ForEachPosition; -} - -export class SwiftTargetLanguage extends TargetLanguage { - public constructor() { - super("Swift", ["swift", "swift4"], "swift"); - } - - protected getOptions(): Array> { - return [ - swiftOptions.justTypes, - swiftOptions.useClasses, - swiftOptions.dense, - swiftOptions.convenienceInitializers, - swiftOptions.explicitCodingKeys, - swiftOptions.codingKeysProtocol, - swiftOptions.accessLevel, - swiftOptions.alamofire, - swiftOptions.linux, - swiftOptions.namedTypePrefix, - swiftOptions.protocol, - swiftOptions.acronymStyle, - swiftOptions.objcSupport, - swiftOptions.optionalEnums, - swiftOptions.sendable, - swiftOptions.swift5Support, - swiftOptions.multiFileOutput, - swiftOptions.mutableProperties - ]; - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - mapping.set("date-time", "date-time"); - return mapping; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): SwiftRenderer { - return new SwiftRenderer(this, renderContext, getOptionValues(swiftOptions, untypedOptionValues)); - } - - public get dateTimeRecognizer(): DateTimeRecognizer { - return new SwiftDateTimeRecognizer(); - } -} +} from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; -const keywords = [ - "await", - "associatedtype", - "class", - "deinit", - "enum", - "extension", - "fileprivate", - "func", - "import", - "init", - "inout", - "internal", - "let", - "open", - "operator", - "private", - "protocol", - "public", - "static", - "struct", - "subscript", - "typealias", - "var", - "break", - "case", - "continue", - "default", - "defer", - "do", - "else", - "fallthrough", - "for", - "guard", - "if", - "in", - "repeat", - "return", - "switch", - "where", - "while", - "as", - "Any", - "catch", - "false", - "is", - "nil", - "rethrows", - "super", - "self", - "Self", - "throw", - "throws", - "true", - "try", - "_", - "associativity", - "convenience", - "dynamic", - "didSet", - "final", - "get", - "infix", - "indirect", - "lazy", - "left", - "mutating", - "nonmutating", - "optional", - "override", - "postfix", - "precedence", - "prefix", - "Protocol", - "required", - "right", - "set", - "Type", - "unowned", - "weak", - "willSet", - "String", - "Int", - "Double", - "Bool", - "Data", - "Date", - "URL", - "CommandLine", - "FileHandle", - "JSONSerialization", - "checkNull", - "removeNSNull", - "nilToNSNull", - "convertArray", - "convertOptional", - "convertDict", - "convertDouble", - "jsonString", - "jsonData" -]; - -function isPartCharacter(codePoint: number): boolean { - return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); -} - -function isStartCharacter(codePoint: number): boolean { - return isPartCharacter(codePoint) && !isDigit(codePoint); -} - -const legalizeName = legalizeCharacters(isPartCharacter); - -function swiftNameStyle( - prefix: string, - isUpper: boolean, - original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle -): string { - const words = splitIntoWords(original); - const combined = combineWords( - words, - legalizeName, - isUpper ? firstUpperWordStyle : allLowerWordStyle, - firstUpperWordStyle, - isUpper ? allUpperWordStyle : allLowerWordStyle, - acronymsStyle, - "", - isStartCharacter - ); - return addPrefixIfNecessary(prefix, combined); -} - -function unicodeEscape(codePoint: number): string { - return "\\u{" + intToHex(codePoint, 0) + "}"; -} - -const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); +import { keywords } from "./constants"; +import { type swiftOptions } from "./language"; +import { MAX_SAMELINE_PROPERTIES, type SwiftProperty, swiftNameStyle } from "./utils"; export class SwiftRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; @@ -348,9 +41,9 @@ export class SwiftRenderer extends ConvenienceRenderer { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { if (this._options.alamofire) { - return ["DataRequest", ...keywords]; + return ["DataRequest", ...keywords] as const; } return keywords; @@ -859,22 +552,22 @@ export class SwiftRenderer extends ConvenienceRenderer { }); } else { this.emitMultiline(`decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in - let container = try decoder.singleValueContainer() - let dateStr = try container.decode(String.self) - - let formatter = DateFormatter() - formatter.calendar = Calendar(identifier: .iso8601) - formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.timeZone = TimeZone(secondsFromGMT: 0) - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" - if let date = formatter.date(from: dateStr) { - return date - } - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX" - if let date = formatter.date(from: dateStr) { - return date - } - throw DecodingError.typeMismatch(Date.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date")) + let container = try decoder.singleValueContainer() + let dateStr = try container.decode(String.self) + + let formatter = DateFormatter() + formatter.calendar = Calendar(identifier: .iso8601) + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" + if let date = formatter.date(from: dateStr) { + return date + } + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX" + if let date = formatter.date(from: dateStr) { + return date + } + throw DecodingError.typeMismatch(Date.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date")) })`); } @@ -1148,20 +841,20 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.ensureBlankLine(); this.emitMultiline(` public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool { - return true - }`); + return true + }`); if (this._options.objcSupport === false) { this.ensureBlankLine(); this.emitMultiline(` public var hashValue: Int { - return 0 - }`); + return 0 + }`); if (this._options.swift5Support) { this.ensureBlankLine(); this.emitMultiline(` public func hash(into hasher: inout Hasher) { - // No-op - }`); + // No-op + }`); } } @@ -1173,41 +866,41 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); } this.emitMultiline(`public init() {} - - public required init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - if !container.decodeNil() { - throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull")) - } - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encodeNil() - } + + public required init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if !container.decodeNil() { + throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull")) + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encodeNil() + } }`); } if (this._needAny) { this.ensureBlankLine(); this.emitMultiline(`class JSONCodingKey: CodingKey { - let key: String - - required init?(intValue: Int) { - return nil - } - - required init?(stringValue: String) { - key = stringValue - } - - var intValue: Int? { - return nil - } - - var stringValue: String { - return key - } + let key: String + + required init?(intValue: Int) { + return nil + } + + required init?(stringValue: String) { + key = stringValue + } + + var intValue: Int? { + return nil + } + + var stringValue: String { + return key + } }`); this.ensureBlankLine(); @@ -1219,196 +912,196 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.ensureBlankLine(); this.emitMultiline(` ${this.accessLevel}let value: Any - - static func decodingError(forCodingPath codingPath: [CodingKey]) -> DecodingError { - let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot decode JSONAny") - return DecodingError.typeMismatch(JSONAny.self, context) - } - - static func encodingError(forValue value: Any, codingPath: [CodingKey]) -> EncodingError { - let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Cannot encode JSONAny") - return EncodingError.invalidValue(value, context) - } - - static func decode(from container: SingleValueDecodingContainer) throws -> Any { - if let value = try? container.decode(Bool.self) { - return value - } - if let value = try? container.decode(Int64.self) { - return value - } - if let value = try? container.decode(Double.self) { - return value - } - if let value = try? container.decode(String.self) { - return value - } - if container.decodeNil() { - return JSONNull() - } - throw decodingError(forCodingPath: container.codingPath) - } - - static func decode(from container: inout UnkeyedDecodingContainer) throws -> Any { - if let value = try? container.decode(Bool.self) { - return value - } - if let value = try? container.decode(Int64.self) { - return value - } - if let value = try? container.decode(Double.self) { - return value - } - if let value = try? container.decode(String.self) { - return value - } - if let value = try? container.decodeNil() { - if value { - return JSONNull() - } - } - if var container = try? container.nestedUnkeyedContainer() { - return try decodeArray(from: &container) - } - if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self) { - return try decodeDictionary(from: &container) - } - throw decodingError(forCodingPath: container.codingPath) - } - - static func decode(from container: inout KeyedDecodingContainer, forKey key: JSONCodingKey) throws -> Any { - if let value = try? container.decode(Bool.self, forKey: key) { - return value - } - if let value = try? container.decode(Int64.self, forKey: key) { - return value - } - if let value = try? container.decode(Double.self, forKey: key) { - return value - } - if let value = try? container.decode(String.self, forKey: key) { - return value - } - if let value = try? container.decodeNil(forKey: key) { - if value { - return JSONNull() - } - } - if var container = try? container.nestedUnkeyedContainer(forKey: key) { - return try decodeArray(from: &container) - } - if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) { - return try decodeDictionary(from: &container) - } - throw decodingError(forCodingPath: container.codingPath) - } - - static func decodeArray(from container: inout UnkeyedDecodingContainer) throws -> [Any] { - var arr: [Any] = [] - while !container.isAtEnd { - let value = try decode(from: &container) - arr.append(value) - } - return arr - } - - static func decodeDictionary(from container: inout KeyedDecodingContainer) throws -> [String: Any] { - var dict = [String: Any]() - for key in container.allKeys { - let value = try decode(from: &container, forKey: key) - dict[key.stringValue] = value - } - return dict - } - - static func encode(to container: inout UnkeyedEncodingContainer, array: [Any]) throws { - for value in array { - if let value = value as? Bool { - try container.encode(value) - } else if let value = value as? Int64 { - try container.encode(value) - } else if let value = value as? Double { - try container.encode(value) - } else if let value = value as? String { - try container.encode(value) - } else if value is JSONNull { - try container.encodeNil() - } else if let value = value as? [Any] { - var container = container.nestedUnkeyedContainer() - try encode(to: &container, array: value) - } else if let value = value as? [String: Any] { - var container = container.nestedContainer(keyedBy: JSONCodingKey.self) - try encode(to: &container, dictionary: value) - } else { - throw encodingError(forValue: value, codingPath: container.codingPath) - } - } - } - - static func encode(to container: inout KeyedEncodingContainer, dictionary: [String: Any]) throws { - for (key, value) in dictionary { - let key = JSONCodingKey(stringValue: key)! - if let value = value as? Bool { - try container.encode(value, forKey: key) - } else if let value = value as? Int64 { - try container.encode(value, forKey: key) - } else if let value = value as? Double { - try container.encode(value, forKey: key) - } else if let value = value as? String { - try container.encode(value, forKey: key) - } else if value is JSONNull { - try container.encodeNil(forKey: key) - } else if let value = value as? [Any] { - var container = container.nestedUnkeyedContainer(forKey: key) - try encode(to: &container, array: value) - } else if let value = value as? [String: Any] { - var container = container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) - try encode(to: &container, dictionary: value) - } else { - throw encodingError(forValue: value, codingPath: container.codingPath) - } - } - } - - static func encode(to container: inout SingleValueEncodingContainer, value: Any) throws { - if let value = value as? Bool { - try container.encode(value) - } else if let value = value as? Int64 { - try container.encode(value) - } else if let value = value as? Double { - try container.encode(value) - } else if let value = value as? String { - try container.encode(value) - } else if value is JSONNull { - try container.encodeNil() - } else { - throw encodingError(forValue: value, codingPath: container.codingPath) - } - } - - public required init(from decoder: Decoder) throws { - if var arrayContainer = try? decoder.unkeyedContainer() { - self.value = try JSONAny.decodeArray(from: &arrayContainer) - } else if var container = try? decoder.container(keyedBy: JSONCodingKey.self) { - self.value = try JSONAny.decodeDictionary(from: &container) - } else { - let container = try decoder.singleValueContainer() - self.value = try JSONAny.decode(from: container) - } - } - - public func encode(to encoder: Encoder) throws { - if let arr = self.value as? [Any] { - var container = encoder.unkeyedContainer() - try JSONAny.encode(to: &container, array: arr) - } else if let dict = self.value as? [String: Any] { - var container = encoder.container(keyedBy: JSONCodingKey.self) - try JSONAny.encode(to: &container, dictionary: dict) - } else { - var container = encoder.singleValueContainer() - try JSONAny.encode(to: &container, value: self.value) - } - } + + static func decodingError(forCodingPath codingPath: [CodingKey]) -> DecodingError { + let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot decode JSONAny") + return DecodingError.typeMismatch(JSONAny.self, context) + } + + static func encodingError(forValue value: Any, codingPath: [CodingKey]) -> EncodingError { + let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Cannot encode JSONAny") + return EncodingError.invalidValue(value, context) + } + + static func decode(from container: SingleValueDecodingContainer) throws -> Any { + if let value = try? container.decode(Bool.self) { + return value + } + if let value = try? container.decode(Int64.self) { + return value + } + if let value = try? container.decode(Double.self) { + return value + } + if let value = try? container.decode(String.self) { + return value + } + if container.decodeNil() { + return JSONNull() + } + throw decodingError(forCodingPath: container.codingPath) + } + + static func decode(from container: inout UnkeyedDecodingContainer) throws -> Any { + if let value = try? container.decode(Bool.self) { + return value + } + if let value = try? container.decode(Int64.self) { + return value + } + if let value = try? container.decode(Double.self) { + return value + } + if let value = try? container.decode(String.self) { + return value + } + if let value = try? container.decodeNil() { + if value { + return JSONNull() + } + } + if var container = try? container.nestedUnkeyedContainer() { + return try decodeArray(from: &container) + } + if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self) { + return try decodeDictionary(from: &container) + } + throw decodingError(forCodingPath: container.codingPath) + } + + static func decode(from container: inout KeyedDecodingContainer, forKey key: JSONCodingKey) throws -> Any { + if let value = try? container.decode(Bool.self, forKey: key) { + return value + } + if let value = try? container.decode(Int64.self, forKey: key) { + return value + } + if let value = try? container.decode(Double.self, forKey: key) { + return value + } + if let value = try? container.decode(String.self, forKey: key) { + return value + } + if let value = try? container.decodeNil(forKey: key) { + if value { + return JSONNull() + } + } + if var container = try? container.nestedUnkeyedContainer(forKey: key) { + return try decodeArray(from: &container) + } + if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) { + return try decodeDictionary(from: &container) + } + throw decodingError(forCodingPath: container.codingPath) + } + + static func decodeArray(from container: inout UnkeyedDecodingContainer) throws -> [Any] { + var arr: [Any] = [] + while !container.isAtEnd { + let value = try decode(from: &container) + arr.append(value) + } + return arr + } + + static func decodeDictionary(from container: inout KeyedDecodingContainer) throws -> [String: Any] { + var dict = [String: Any]() + for key in container.allKeys { + let value = try decode(from: &container, forKey: key) + dict[key.stringValue] = value + } + return dict + } + + static func encode(to container: inout UnkeyedEncodingContainer, array: [Any]) throws { + for value in array { + if let value = value as? Bool { + try container.encode(value) + } else if let value = value as? Int64 { + try container.encode(value) + } else if let value = value as? Double { + try container.encode(value) + } else if let value = value as? String { + try container.encode(value) + } else if value is JSONNull { + try container.encodeNil() + } else if let value = value as? [Any] { + var container = container.nestedUnkeyedContainer() + try encode(to: &container, array: value) + } else if let value = value as? [String: Any] { + var container = container.nestedContainer(keyedBy: JSONCodingKey.self) + try encode(to: &container, dictionary: value) + } else { + throw encodingError(forValue: value, codingPath: container.codingPath) + } + } + } + + static func encode(to container: inout KeyedEncodingContainer, dictionary: [String: Any]) throws { + for (key, value) in dictionary { + let key = JSONCodingKey(stringValue: key)! + if let value = value as? Bool { + try container.encode(value, forKey: key) + } else if let value = value as? Int64 { + try container.encode(value, forKey: key) + } else if let value = value as? Double { + try container.encode(value, forKey: key) + } else if let value = value as? String { + try container.encode(value, forKey: key) + } else if value is JSONNull { + try container.encodeNil(forKey: key) + } else if let value = value as? [Any] { + var container = container.nestedUnkeyedContainer(forKey: key) + try encode(to: &container, array: value) + } else if let value = value as? [String: Any] { + var container = container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) + try encode(to: &container, dictionary: value) + } else { + throw encodingError(forValue: value, codingPath: container.codingPath) + } + } + } + + static func encode(to container: inout SingleValueEncodingContainer, value: Any) throws { + if let value = value as? Bool { + try container.encode(value) + } else if let value = value as? Int64 { + try container.encode(value) + } else if let value = value as? Double { + try container.encode(value) + } else if let value = value as? String { + try container.encode(value) + } else if value is JSONNull { + try container.encodeNil() + } else { + throw encodingError(forValue: value, codingPath: container.codingPath) + } + } + + public required init(from decoder: Decoder) throws { + if var arrayContainer = try? decoder.unkeyedContainer() { + self.value = try JSONAny.decodeArray(from: &arrayContainer) + } else if var container = try? decoder.container(keyedBy: JSONCodingKey.self) { + self.value = try JSONAny.decodeDictionary(from: &container) + } else { + let container = try decoder.singleValueContainer() + self.value = try JSONAny.decode(from: container) + } + } + + public func encode(to encoder: Encoder) throws { + if let arr = self.value as? [Any] { + var container = encoder.unkeyedContainer() + try JSONAny.encode(to: &container, array: arr) + } else if let dict = self.value as? [String: Any] { + var container = encoder.container(keyedBy: JSONCodingKey.self) + try JSONAny.encode(to: &container, dictionary: dict) + } else { + var container = encoder.singleValueContainer() + try JSONAny.encode(to: &container, value: self.value) + } + } }`); } @@ -1472,20 +1165,20 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.emitBlockWithAccess("extension DataRequest", () => { this .emitMultiline(`fileprivate func decodableResponseSerializer() -> DataResponseSerializer { - return DataResponseSerializer { _, response, data, error in - guard error == nil else { return .failure(error!) } - - guard let data = data else { - return .failure(AFError.responseSerializationFailed(reason: .inputDataNil)) - } - - return Result { try newJSONDecoder().decode(T.self, from: data) } - } + return DataResponseSerializer { _, response, data, error in + guard error == nil else { return .failure(error!) } + + guard let data = data else { + return .failure(AFError.responseSerializationFailed(reason: .inputDataNil)) + } + + return Result { try newJSONDecoder().decode(T.self, from: data) } + } } @discardableResult fileprivate func responseDecodable(queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self { - return response(queue: queue, responseSerializer: decodableResponseSerializer(), completionHandler: completionHandler) + return response(queue: queue, responseSerializer: decodableResponseSerializer(), completionHandler: completionHandler) }`); this.ensureBlankLine(); this.forEachTopLevel("leading-and-interposing", (_, name) => { diff --git a/packages/quicktype-core/src/language/Swift/constants.ts b/packages/quicktype-core/src/language/Swift/constants.ts new file mode 100644 index 000000000..4a8c4ee2f --- /dev/null +++ b/packages/quicktype-core/src/language/Swift/constants.ts @@ -0,0 +1,101 @@ +export const keywords = [ + "await", + "associatedtype", + "class", + "deinit", + "enum", + "extension", + "fileprivate", + "func", + "import", + "init", + "inout", + "internal", + "let", + "open", + "operator", + "private", + "protocol", + "public", + "static", + "struct", + "subscript", + "typealias", + "var", + "break", + "case", + "continue", + "default", + "defer", + "do", + "else", + "fallthrough", + "for", + "guard", + "if", + "in", + "repeat", + "return", + "switch", + "where", + "while", + "as", + "Any", + "catch", + "false", + "is", + "nil", + "rethrows", + "super", + "self", + "Self", + "throw", + "throws", + "true", + "try", + "_", + "associativity", + "convenience", + "dynamic", + "didSet", + "final", + "get", + "infix", + "indirect", + "lazy", + "left", + "mutating", + "nonmutating", + "optional", + "override", + "postfix", + "precedence", + "prefix", + "Protocol", + "required", + "right", + "set", + "Type", + "unowned", + "weak", + "willSet", + "String", + "Int", + "Double", + "Bool", + "Data", + "Date", + "URL", + "CommandLine", + "FileHandle", + "JSONSerialization", + "checkNull", + "removeNSNull", + "nilToNSNull", + "convertArray", + "convertOptional", + "convertDict", + "convertDouble", + "jsonString", + "jsonData" +] as const; diff --git a/packages/quicktype-core/src/language/Swift/index.ts b/packages/quicktype-core/src/language/Swift/index.ts new file mode 100644 index 000000000..902d4fff7 --- /dev/null +++ b/packages/quicktype-core/src/language/Swift/index.ts @@ -0,0 +1,2 @@ +export { SwiftTargetLanguage, swiftOptions } from "./language"; +export { SwiftRenderer } from "./SwiftRenderer"; diff --git a/packages/quicktype-core/src/language/Swift/language.ts b/packages/quicktype-core/src/language/Swift/language.ts new file mode 100644 index 000000000..152e932af --- /dev/null +++ b/packages/quicktype-core/src/language/Swift/language.ts @@ -0,0 +1,128 @@ +import { type DateTimeRecognizer } from "../../DateTime"; +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { SwiftRenderer } from "./SwiftRenderer"; +import { SwiftDateTimeRecognizer } from "./utils"; + +export const swiftOptions = { + justTypes: new BooleanOption("just-types", "Plain types only", false), + convenienceInitializers: new BooleanOption("initializers", "Generate initializers and mutators", true), + explicitCodingKeys: new BooleanOption("coding-keys", "Explicit CodingKey values in Codable types", true), + codingKeysProtocol: new StringOption( + "coding-keys-protocol", + "CodingKeys implements protocols", + "protocol1, protocol2...", + "", + "secondary" + ), + alamofire: new BooleanOption("alamofire", "Alamofire extensions", false), + namedTypePrefix: new StringOption("type-prefix", "Prefix for type names", "PREFIX", "", "secondary"), + useClasses: new EnumOption("struct-or-class", "Structs or classes", [ + ["struct", false], + ["class", true] + ]), + mutableProperties: new BooleanOption("mutable-properties", "Use var instead of let for object properties", false), + acronymStyle: acronymOption(AcronymStyleOptions.Pascal), + dense: new EnumOption( + "density", + "Code density", + [ + ["dense", true], + ["normal", false] + ], + "dense", + "secondary" + ), + linux: new BooleanOption("support-linux", "Support Linux", false, "secondary"), + objcSupport: new BooleanOption( + "objective-c-support", + "Objects inherit from NSObject and @objcMembers is added to classes", + false + ), + optionalEnums: new BooleanOption("optional-enums", "If no matching case is found enum value is set to null", false), + swift5Support: new BooleanOption("swift-5-support", "Renders output in a Swift 5 compatible mode", false), + sendable: new BooleanOption("sendable", "Mark generated models as Sendable", false), + multiFileOutput: new BooleanOption( + "multi-file-output", + "Renders each top-level object in its own Swift file", + false + ), + accessLevel: new EnumOption( + "access-level", + "Access level", + [ + ["internal", "internal"], + ["public", "public"] + ], + "internal", + "secondary" + ), + protocol: new EnumOption( + "protocol", + "Make types implement protocol", + [ + ["none", { equatable: false, hashable: false }], + ["equatable", { equatable: true, hashable: false }], + ["hashable", { equatable: false, hashable: true }] + ], + "none", + "secondary" + ) +}; + +export class SwiftTargetLanguage extends TargetLanguage { + public constructor() { + super("Swift", ["swift", "swift4"], "swift"); + } + + protected getOptions(): Array> { + return [ + swiftOptions.justTypes, + swiftOptions.useClasses, + swiftOptions.dense, + swiftOptions.convenienceInitializers, + swiftOptions.explicitCodingKeys, + swiftOptions.codingKeysProtocol, + swiftOptions.accessLevel, + swiftOptions.alamofire, + swiftOptions.linux, + swiftOptions.namedTypePrefix, + swiftOptions.protocol, + swiftOptions.acronymStyle, + swiftOptions.objcSupport, + swiftOptions.optionalEnums, + swiftOptions.sendable, + swiftOptions.swift5Support, + swiftOptions.multiFileOutput, + swiftOptions.mutableProperties + ]; + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + mapping.set("date-time", "date-time"); + return mapping; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): SwiftRenderer { + return new SwiftRenderer(this, renderContext, getOptionValues(swiftOptions, untypedOptionValues)); + } + + public get dateTimeRecognizer(): DateTimeRecognizer { + return new SwiftDateTimeRecognizer(); + } +} diff --git a/packages/quicktype-core/src/language/Swift/utils.ts b/packages/quicktype-core/src/language/Swift/utils.ts new file mode 100644 index 000000000..34d5ace85 --- /dev/null +++ b/packages/quicktype-core/src/language/Swift/utils.ts @@ -0,0 +1,84 @@ +import { ClassProperty } from "../../Type"; +import { Name } from "../../Naming"; +import { + legalizeCharacters, + isLetterOrUnderscore, + isNumeric, + isDigit, + utf32ConcatMap, + escapeNonPrintableMapper, + isPrintable, + intToHex, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allLowerWordStyle, + allUpperWordStyle, + addPrefixIfNecessary +} from "../../support/Strings"; +import { ForEachPosition } from "../../Renderer"; +import { DefaultDateTimeRecognizer } from "../../DateTime"; + +export const MAX_SAMELINE_PROPERTIES = 4; + +// These are all recognized by Swift as ISO8601 date-times: +// +// 2018-08-14T02:45:50+00:00 +// 2018-08-14T02:45:50+00 +// 2018-08-14T02:45:50+1 +// 2018-08-14T02:45:50+1111 +// 2018-08-14T02:45:50+1111:1:33 +// 2018-08-14T02:45:50-00 +// 2018-08-14T02:45:50z +// 2018-00008-1T002:45:3Z + +const swiftDateTimeRegex = /^\d+-\d+-\d+T\d+:\d+:\d+([zZ]|[+-]\d+(:\d+)?)$/; + +export class SwiftDateTimeRecognizer extends DefaultDateTimeRecognizer { + isDateTime(str: string): boolean { + return str.match(swiftDateTimeRegex) !== null; + } +} + +export interface SwiftProperty { + name: Name; + jsonName: string; + parameter: ClassProperty; + position: ForEachPosition; +} + +function isPartCharacter(codePoint: number): boolean { + return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); +} + +function isStartCharacter(codePoint: number): boolean { + return isPartCharacter(codePoint) && !isDigit(codePoint); +} + +const legalizeName = legalizeCharacters(isPartCharacter); + +export function swiftNameStyle( + prefix: string, + isUpper: boolean, + original: string, + acronymsStyle: (s: string) => string = allUpperWordStyle +): string { + const words = splitIntoWords(original); + const combined = combineWords( + words, + legalizeName, + isUpper ? firstUpperWordStyle : allLowerWordStyle, + firstUpperWordStyle, + isUpper ? allUpperWordStyle : allLowerWordStyle, + acronymsStyle, + "", + isStartCharacter + ); + return addPrefixIfNecessary(prefix, combined); +} + +function unicodeEscape(codePoint: number): string { + return "\\u{" + intToHex(codePoint, 0) + "}"; +} + +export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); From aa4d99ddf59822fdfcf8fd6304dcfc325cfbc20a Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 11:41:39 -0700 Subject: [PATCH 43/80] move Smithy4s to own dir --- .../Smithy4sRenderer.ts} | 201 ++---------------- .../src/language/Smithy4s/constants.ts | 77 +++++++ .../src/language/Smithy4s/index.ts | 2 + .../src/language/Smithy4s/language.ts | 46 ++++ .../src/language/Smithy4s/utils.ts | 53 +++++ 5 files changed, 196 insertions(+), 183 deletions(-) rename packages/quicktype-core/src/language/{Smithy4s.ts => Smithy4s/Smithy4sRenderer.ts} (73%) create mode 100644 packages/quicktype-core/src/language/Smithy4s/constants.ts create mode 100644 packages/quicktype-core/src/language/Smithy4s/index.ts create mode 100644 packages/quicktype-core/src/language/Smithy4s/language.ts create mode 100644 packages/quicktype-core/src/language/Smithy4s/utils.ts diff --git a/packages/quicktype-core/src/language/Smithy4s.ts b/packages/quicktype-core/src/language/Smithy4s/Smithy4sRenderer.ts similarity index 73% rename from packages/quicktype-core/src/language/Smithy4s.ts rename to packages/quicktype-core/src/language/Smithy4s/Smithy4sRenderer.ts index 163b33073..17fda57b2 100644 --- a/packages/quicktype-core/src/language/Smithy4s.ts +++ b/packages/quicktype-core/src/language/Smithy4s/Smithy4sRenderer.ts @@ -1,22 +1,10 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated } from "../Source"; -import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - firstUpperWordStyle, - isDigit, - isLetterOrUnderscore, - isNumeric, - legalizeCharacters, - splitIntoWords -} from "../support/Strings"; -import { assertNever } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { type TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, @@ -26,147 +14,23 @@ import { type ObjectType, type Type, type UnionType -} from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchCompoundType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export enum Framework { - None = "None" -} +} from "../../Type"; +import { matchCompoundType, matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; -export const SmithyOptions = { - framework: new EnumOption("framework", "Serialization framework", [["just-types", Framework.None]], undefined), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") -}; - -// Use backticks for param names with symbols -const invalidSymbols = [ - ":", - "-", - "+", - "!", - "@", - "#", - "%", - "^", - "&", - "*", - "(", - ")", - ">", - "<", - "/", - ";", - "'", - '"', - "{", - "}", - ":", - "~", - "`", - "." -]; - -const keywords = [ - "abstract", - "case", - "catch", - "do", - "else", - "export", - "false", - "final", - "finally", - "for", - "forSome", - "if", - "implicit", - "import", - "new", - "override", - "package", - "private", - "protected", - "return", - "sealed", - "super", - "this", - "then", - "throw", - "trait", - "try", - "true", - "val", - "var", - "while", - "with", - "yield", - "Any", - "Boolean", - "Double", - "Float", - "Long", - "Int", - "Short", - "System", - "Byte", - "String", - "Array", - "List", - "Map", - "Enum" -]; - -/** - * Check if given parameter name should be wrapped in a backtick - * @param paramName - */ -const shouldAddBacktick = (paramName: string): boolean => { - return ( - keywords.some(s => paramName === s) || - invalidSymbols.some(s => paramName.includes(s)) || - !isNaN(parseFloat(paramName)) || - !isNaN(parseInt(paramName.charAt(0))) - ); -}; - -function isPartCharacter(codePoint: number): boolean { - return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); -} - -function isStartCharacter(codePoint: number): boolean { - return isPartCharacter(codePoint) && !isDigit(codePoint); -} - -const legalizeName = legalizeCharacters(isPartCharacter); - -function scalaNameStyle(isUpper: boolean, original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - isUpper ? firstUpperWordStyle : allLowerWordStyle, - firstUpperWordStyle, - isUpper ? allUpperWordStyle : allLowerWordStyle, - allUpperWordStyle, - "", - isStartCharacter - ); -} - -const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s)); -const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); +import { keywords } from "./constants"; +import { type smithyOptions } from "./language"; +import { lowerNamingFunction, scalaNameStyle, shouldAddBacktick, upperNamingFunction } from "./utils"; export class Smithy4sRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _scalaOptions: OptionValues + protected readonly _scalaOptions: OptionValues ) { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return keywords; } @@ -419,10 +283,10 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.forEachEnumCase(e, "none", (name, jsonName) => { // if (!(jsonName == "")) { /* const backticks = - shouldAddBacktick(jsonName) || - jsonName.includes(" ") || - !isNaN(parseInt(jsonName.charAt(0))) - if (backticks) {this.emitItem("`")} else */ + shouldAddBacktick(jsonName) || + jsonName.includes(" ") || + !isNaN(parseInt(jsonName.charAt(0))) + if (backticks) {this.emitItem("`")} else */ this.emitLine(); this.emitItem([name, ' = "', jsonName, '"']); @@ -524,32 +388,3 @@ export class Smithy4sRenderer extends ConvenienceRenderer { ); } } - -export class SmithyTargetLanguage extends TargetLanguage { - public constructor() { - super("Smithy", ["Smithy"], "smithy"); - } - - protected getOptions(): Array> { - return [SmithyOptions.framework, SmithyOptions.packageName]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { - const options = getOptionValues(SmithyOptions, untypedOptionValues); - - switch (options.framework) { - case Framework.None: - return new Smithy4sRenderer(this, renderContext, options); - default: - return assertNever(options.framework); - } - } -} diff --git a/packages/quicktype-core/src/language/Smithy4s/constants.ts b/packages/quicktype-core/src/language/Smithy4s/constants.ts new file mode 100644 index 000000000..e015b6ea8 --- /dev/null +++ b/packages/quicktype-core/src/language/Smithy4s/constants.ts @@ -0,0 +1,77 @@ +// Use backticks for param names with symbols +export const invalidSymbols = [ + ":", + "-", + "+", + "!", + "@", + "#", + "%", + "^", + "&", + "*", + "(", + ")", + ">", + "<", + "/", + ";", + "'", + '"', + "{", + "}", + ":", + "~", + "`", + "." +] as const; + +export const keywords = [ + "abstract", + "case", + "catch", + "do", + "else", + "export", + "false", + "final", + "finally", + "for", + "forSome", + "if", + "implicit", + "import", + "new", + "override", + "package", + "private", + "protected", + "return", + "sealed", + "super", + "this", + "then", + "throw", + "trait", + "try", + "true", + "val", + "var", + "while", + "with", + "yield", + "Any", + "Boolean", + "Double", + "Float", + "Long", + "Int", + "Short", + "System", + "Byte", + "String", + "Array", + "List", + "Map", + "Enum" +] as const; diff --git a/packages/quicktype-core/src/language/Smithy4s/index.ts b/packages/quicktype-core/src/language/Smithy4s/index.ts new file mode 100644 index 000000000..1dea97f90 --- /dev/null +++ b/packages/quicktype-core/src/language/Smithy4s/index.ts @@ -0,0 +1,2 @@ +export { SmithyTargetLanguage, smithyOptions } from "./language"; +export { Smithy4sRenderer } from "./Smithy4sRenderer"; diff --git a/packages/quicktype-core/src/language/Smithy4s/language.ts b/packages/quicktype-core/src/language/Smithy4s/language.ts new file mode 100644 index 000000000..2726d0ff5 --- /dev/null +++ b/packages/quicktype-core/src/language/Smithy4s/language.ts @@ -0,0 +1,46 @@ +import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type RenderContext } from "../../Renderer"; +import { EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { assertNever } from "../../support/Support"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { Smithy4sRenderer } from "./Smithy4sRenderer"; + +export enum Framework { + None = "None" +} + +export const smithyOptions = { + framework: new EnumOption("framework", "Serialization framework", [["just-types", Framework.None]], undefined), + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") +}; + +export class SmithyTargetLanguage extends TargetLanguage { + public constructor() { + super("Smithy", ["Smithy"], "smithy"); + } + + protected getOptions(): Array> { + return [smithyOptions.framework, smithyOptions.packageName]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { + const options = getOptionValues(smithyOptions, untypedOptionValues); + + switch (options.framework) { + case Framework.None: + return new Smithy4sRenderer(this, renderContext, options); + default: + return assertNever(options.framework); + } + } +} diff --git a/packages/quicktype-core/src/language/Smithy4s/utils.ts b/packages/quicktype-core/src/language/Smithy4s/utils.ts new file mode 100644 index 000000000..6683ac138 --- /dev/null +++ b/packages/quicktype-core/src/language/Smithy4s/utils.ts @@ -0,0 +1,53 @@ +import { funPrefixNamer } from "../../Naming"; +import { + isLetterOrUnderscore, + isNumeric, + legalizeCharacters, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allLowerWordStyle, + allUpperWordStyle +} from "../../support/Strings"; +import { isDigit } from "unicode-properties"; +import { keywords, invalidSymbols } from "./constants"; + +/** + * Check if given parameter name should be wrapped in a backtick + * @param paramName + */ +export const shouldAddBacktick = (paramName: string): boolean => { + return ( + keywords.some(s => paramName === s) || + invalidSymbols.some(s => paramName.includes(s)) || + !isNaN(parseFloat(paramName)) || + !isNaN(parseInt(paramName.charAt(0))) + ); +}; + +function isPartCharacter(codePoint: number): boolean { + return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); +} + +function isStartCharacter(codePoint: number): boolean { + return isPartCharacter(codePoint) && !isDigit(codePoint); +} + +const legalizeName = legalizeCharacters(isPartCharacter); + +export function scalaNameStyle(isUpper: boolean, original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + isUpper ? firstUpperWordStyle : allLowerWordStyle, + firstUpperWordStyle, + isUpper ? allUpperWordStyle : allLowerWordStyle, + allUpperWordStyle, + "", + isStartCharacter + ); +} + +export const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s)); +export const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); From 2a3fb7cc923521e34db454eab7fd2924139ba0f1 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 11:47:38 -0700 Subject: [PATCH 44/80] move Scala3 to own dir --- .../quicktype-core/src/language/Scala3.ts | 721 ------------------ .../src/language/Scala3/CirceRenderer.ts | 193 +++++ .../src/language/Scala3/Scala3Renderer.ts | 313 ++++++++ .../src/language/Scala3/UpickleRenderer.ts | 14 + .../src/language/Scala3/constants.ts | 87 +++ .../src/language/Scala3/index.ts | 4 + .../src/language/Scala3/language.ts | 63 ++ .../src/language/Scala3/utils.ts | 72 ++ 8 files changed, 746 insertions(+), 721 deletions(-) delete mode 100644 packages/quicktype-core/src/language/Scala3.ts create mode 100644 packages/quicktype-core/src/language/Scala3/CirceRenderer.ts create mode 100644 packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts create mode 100644 packages/quicktype-core/src/language/Scala3/UpickleRenderer.ts create mode 100644 packages/quicktype-core/src/language/Scala3/constants.ts create mode 100644 packages/quicktype-core/src/language/Scala3/index.ts create mode 100644 packages/quicktype-core/src/language/Scala3/language.ts create mode 100644 packages/quicktype-core/src/language/Scala3/utils.ts diff --git a/packages/quicktype-core/src/language/Scala3.ts b/packages/quicktype-core/src/language/Scala3.ts deleted file mode 100644 index 75da0773f..000000000 --- a/packages/quicktype-core/src/language/Scala3.ts +++ /dev/null @@ -1,721 +0,0 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated } from "../Source"; -import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - firstUpperWordStyle, - isDigit, - isLetterOrUnderscore, - isNumeric, - legalizeCharacters, - splitIntoWords -} from "../support/Strings"; -import { assertNever } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { - ArrayType, - type ClassProperty, - type ClassType, - type EnumType, - MapType, - type ObjectType, - type Type, - type UnionType -} from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export enum Framework { - None = "None", - Upickle = "Upickle", - Circe = "Circe" -} - -export const scala3Options = { - framework: new EnumOption( - "framework", - "Serialization framework", - [ - ["just-types", Framework.None], - ["circe", Framework.Circe], - ["upickle", Framework.Upickle] - ], - undefined - ), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") -}; - -// Use backticks for param names with symbols -const invalidSymbols = [ - ":", - "-", - "+", - "!", - "@", - "#", - "$", - "%", - "^", - "&", - "*", - "(", - ")", - ">", - "<", - "/", - ";", - "'", - '"', - "{", - "}", - ":", - "~", - "`", - "." -]; - -const keywords = [ - "abstract", - "case", - "catch", - "class", - "def", - "do", - "else", - "enum", - "extends", - "export", - "false", - "final", - "finally", - "for", - "forSome", - "if", - "implicit", - "import", - "lazy", - "match", - "new", - "null", - "object", - "override", - "package", - "private", - "protected", - "return", - "sealed", - "super", - "this", - "then", - "throw", - "trait", - "try", - "true", - "type", - "val", - "var", - "while", - "with", - "yield", - "Any", - "Boolean", - "Double", - "Float", - "Long", - "Int", - "Short", - "System", - "Byte", - "String", - "Array", - "List", - "Map", - "Enum" -]; - -/** - * Check if given parameter name should be wrapped in a backtick - * @param paramName - */ -const shouldAddBacktick = (paramName: string): boolean => { - return ( - keywords.some(s => paramName === s) || - invalidSymbols.some(s => paramName.includes(s)) || - !isNaN(+parseFloat(paramName)) || - !isNaN(parseInt(paramName.charAt(0))) - ); -}; - -const wrapOption = (s: string, optional: boolean): string => { - if (optional) { - return "Option[" + s + "]"; - } else { - return s; - } -}; - -function isPartCharacter(codePoint: number): boolean { - return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); -} - -function isStartCharacter(codePoint: number): boolean { - return isPartCharacter(codePoint) && !isDigit(codePoint); -} - -const legalizeName = legalizeCharacters(isPartCharacter); - -function scalaNameStyle(isUpper: boolean, original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - isUpper ? firstUpperWordStyle : allLowerWordStyle, - firstUpperWordStyle, - isUpper ? allUpperWordStyle : allLowerWordStyle, - allUpperWordStyle, - "", - isStartCharacter - ); -} - -/* function unicodeEscape(codePoint: number): string { - return "\\u" + intToHex(codePoint, 4); -} */ - -// const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); - -/* function stringEscape(s: string): string { - // "$this" is a template string in Kotlin so we have to escape $ - return _stringEscape(s).replace(/\$/g, "\\$"); -} */ - -const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s)); -const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); - -export class Scala3Renderer extends ConvenienceRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - protected readonly _scalaOptions: OptionValues - ) { - super(targetLanguage, renderContext); - } - - protected forbiddenNamesForGlobalNamespace(): string[] { - return keywords; - } - - protected forbiddenForObjectProperties(_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { - return { names: [], includeGlobalForbidden: true }; - } - - protected forbiddenForEnumCases(_: EnumType, _enumName: Name): ForbiddenWordsInfo { - return { names: [], includeGlobalForbidden: true }; - } - - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { - return { names: [], includeGlobalForbidden: false }; - } - - protected topLevelNameStyle(rawName: string): string { - return scalaNameStyle(true, rawName); - } - - protected makeNamedTypeNamer(): Namer { - return upperNamingFunction; - } - - protected namerForObjectProperty(): Namer { - return lowerNamingFunction; - } - - protected makeUnionMemberNamer(): Namer { - return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); - } - - protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate - } - - protected emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); - } - - protected emitBlock( - line: Sourcelike, - f: () => void, - delimiter: "curly" | "paren" | "lambda" | "none" = "curly" - ): void { - const [open, close] = - delimiter === "curly" - ? ["{", "}"] - : delimiter === "paren" - ? ["(", ")"] - : delimiter === "none" - ? ["", ""] - : ["{", "})"]; - this.emitLine(line, " ", open); - this.indent(f); - this.emitLine(close); - } - - protected anySourceType(optional: boolean): Sourcelike { - return [wrapOption("Any", optional)]; - } - - // (asarazan): I've broken out the following two functions - // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType(arrayType: ArrayType, withIssues = false): Sourcelike { - return ["Seq[", this.scalaType(arrayType.items, withIssues), "]"]; - } - - protected mapType(mapType: MapType, withIssues = false): Sourcelike { - return ["Map[String, ", this.scalaType(mapType.values, withIssues), "]"]; - } - - protected scalaType(t: Type, withIssues = false, noOptional = false): Sourcelike { - return matchType( - t, - _anyType => { - return maybeAnnotated(withIssues, anyTypeIssueAnnotation, this.anySourceType(!noOptional)); - }, - _nullType => { - // return "None.type" - return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(!noOptional)); - }, - _boolType => "Boolean", - _integerType => "Long", - _doubleType => "Double", - _stringType => "String", - arrayType => this.arrayType(arrayType, withIssues), - classType => this.nameForNamedType(classType), - mapType => this.mapType(mapType, withIssues), - enumType => this.nameForNamedType(enumType), - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - if (noOptional) { - return [this.scalaType(nullable, withIssues)]; - } else { - return ["Option[", this.scalaType(nullable, withIssues), "]"]; - } - } - - return this.nameForNamedType(unionType); - } - ); - } - - protected emitUsageHeader(): void { - // To be overridden - } - - protected emitHeader(): void { - if (this.leadingComments !== undefined) { - this.emitComments(this.leadingComments); - } else { - this.emitUsageHeader(); - } - - this.ensureBlankLine(); - this.emitLine("package ", this._scalaOptions.packageName); - this.ensureBlankLine(); - } - - protected emitTopLevelArray(t: ArrayType, name: Name): void { - const elementType = this.scalaType(t.items); - this.emitLine(["type ", name, " = List[", elementType, "]"]); - } - - protected emitTopLevelMap(t: MapType, name: Name): void { - const elementType = this.scalaType(t.values); - this.emitLine(["type ", name, " = Map[String, ", elementType, "]"]); - } - - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { - this.emitDescription(this.descriptionForType(c)); - this.emitLine("case class ", className, "()"); - } - - protected emitClassDefinition(c: ClassType, className: Name): void { - if (c.getProperties().size === 0) { - this.emitEmptyClassDefinition(c, className); - return; - } - - const scalaType = (p: ClassProperty): Sourcelike => { - if (p.isOptional) { - return ["Option[", this.scalaType(p.type, true, true), "]"]; - } else { - return this.scalaType(p.type, true); - } - }; - - this.emitDescription(this.descriptionForType(c)); - this.emitLine("case class ", className, " ("); - this.indent(() => { - let count = c.getProperties().size; - let first = true; - this.forEachClassProperty(c, "none", (_, jsonName, p) => { - const nullable = p.type.kind === "union" && nullableFromUnion(p.type as UnionType) !== null; - const nullableOrOptional = p.isOptional || p.type.kind === "null" || nullable; - const last = --count === 0; - const meta: Array<() => void> = []; - - const description = this.descriptionForClassProperty(c, jsonName); - if (description !== undefined) { - meta.push(() => this.emitDescription(description)); - } - - if (meta.length > 0 && !first) { - this.ensureBlankLine(); - } - - for (const emit of meta) { - emit(); - } - - const nameNeedsBackticks = jsonName.endsWith("_") || shouldAddBacktick(jsonName); - const nameWithBackticks = nameNeedsBackticks ? "`" + jsonName + "`" : jsonName; - this.emitLine( - "val ", - nameWithBackticks, - " : ", - scalaType(p), - p.isOptional ? " = None" : nullableOrOptional ? " = None" : "", - last ? "" : "," - ); - - if (meta.length > 0 && !last) { - this.ensureBlankLine(); - } - - first = false; - }); - }); - - this.emitClassDefinitionMethods(); - } - - protected emitClassDefinitionMethods(): void { - this.emitLine(")"); - } - - protected emitEnumDefinition(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - - this.emitBlock( - ["enum ", enumName, " : "], - () => { - let count = e.cases.size; - if (count > 0) { - this.emitItem("\t case "); - } - - this.forEachEnumCase(e, "none", (name, jsonName) => { - if (!(jsonName == "")) { - const backticks = - shouldAddBacktick(jsonName) || - jsonName.includes(" ") || - !isNaN(parseInt(jsonName.charAt(0))); - if (backticks) { - this.emitItem("`"); - } - - this.emitItemOnce([name]); - if (backticks) { - this.emitItem("`"); - } - - if (--count > 0) this.emitItem([","]); - } else { - --count; - } - }); - }, - "none" - ); - } - - protected emitUnionDefinition(u: UnionType, unionName: Name): void { - function sortBy(t: Type): string { - const kind = t.kind; - if (kind === "class") return kind; - return "_" + kind; - } - - this.emitDescription(this.descriptionForType(u)); - - const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); - const theTypes: Sourcelike[] = []; - this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { - theTypes.push(this.scalaType(t)); - }); - if (maybeNull !== null) { - theTypes.push(this.nameForUnionMember(u, maybeNull)); - } - - this.emitItem(["type ", unionName, " = "]); - theTypes.forEach((t, i) => { - this.emitItem(i === 0 ? t : [" | ", t]); - }); - this.ensureBlankLine(); - } - - protected emitSourceStructure(): void { - this.emitHeader(); - - // Top-level arrays, maps - this.forEachTopLevel("leading", (t, name) => { - if (t instanceof ArrayType) { - this.emitTopLevelArray(t, name); - } else if (t instanceof MapType) { - this.emitTopLevelMap(t, name); - } - }); - - this.forEachNamedType( - "leading-and-interposing", - (c: ClassType, n: Name) => this.emitClassDefinition(c, n), - (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n) - ); - } -} - -export class UpickleRenderer extends Scala3Renderer { - protected emitClassDefinitionMethods(): void { - this.emitLine(") derives ReadWriter "); - } - - protected emitHeader(): void { - super.emitHeader(); - - this.emitLine("import upickle.default.*"); - this.ensureBlankLine(); - } -} - -export class CirceRenderer extends Scala3Renderer { - private seenUnionTypes: string[] = []; - - protected circeEncoderForType(t: Type, __ = false, noOptional = false, paramName: string = ""): Sourcelike { - return matchType( - t, - _anyType => ["Encoder.encodeJson(", paramName, ")"], - _nullType => ["Encoder.encodeNone(", paramName, ")"], - _boolType => ["Encoder.encodeBoolean(", paramName, ")"], - _integerType => ["Encoder.encodeLong(", paramName, ")"], - _doubleType => ["Encoder.encodeDouble(", paramName, ")"], - _stringType => ["Encoder.encodeString(", paramName, ")"], - arrayType => ["Encoder.encodeSeq[", this.scalaType(arrayType.items), "].apply(", paramName, ")"], - classType => ["Encoder.AsObject[", this.scalaType(classType), "].apply(", paramName, ")"], - mapType => ["Encoder.encodeMap[String,", this.scalaType(mapType.values), "].apply(", paramName, ")"], - _ => ["Encoder.encodeString(", paramName, ")"], - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - if (noOptional) { - return ["Encoder.AsObject[", this.nameForNamedType(nullable), "]"]; - } else { - return ["Encoder.AsObject[Option[", this.nameForNamedType(nullable), "]]"]; - } - } - - return ["Encoder.AsObject[", this.nameForNamedType(unionType), "]"]; - } - ); - } - - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { - this.emitDescription(this.descriptionForType(c)); - this.ensureBlankLine(); - this.emitLine("case class ", className, "() derives Encoder.AsObject, Decoder"); - } - - protected anySourceType(optional: boolean): Sourcelike { - return [wrapOption("Json", optional)]; - } - - protected emitClassDefinitionMethods(): void { - this.emitLine(") derives Encoder.AsObject, Decoder"); - } - - protected emitEnumDefinition(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - - this.ensureBlankLine(); - this.emitItem(["type ", enumName, " = "]); - let count = e.cases.size; - this.forEachEnumCase(e, "none", (_, jsonName) => { - // if (!(jsonName == "")) { - /* const backticks = - shouldAddBacktick(jsonName) || - jsonName.includes(" ") || - !isNaN(parseInt(jsonName.charAt(0))) - if (backticks) {this.emitItem("`")} else */ - this.emitItem(['"', jsonName, '"']); - // if (backticks) {this.emitItem("`")} - if (--count > 0) this.emitItem([" | "]); - // } else { - // --count - // } - }); - this.ensureBlankLine(); - } - - protected emitHeader(): void { - super.emitHeader(); - - this.emitLine("import scala.util.Try"); - this.emitLine("import io.circe.syntax._"); - this.emitLine("import io.circe._"); - this.emitLine("import cats.syntax.functor._"); - this.ensureBlankLine(); - - this.emitLine("// For serialising string unions"); - this.emitLine( - "given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) " - ); - this.emitLine( - "given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) " - ); - this.ensureBlankLine(); - this.emitLine("// If a union has a null in, then we'll need this too... "); - this.emitLine("type NullValue = None.type"); - } - - protected emitTopLevelArray(t: ArrayType, name: Name): void { - super.emitTopLevelArray(t, name); - const elementType = this.scalaType(t.items); - this.emitLine([ - "given (using ev : ", - elementType, - "): Encoder[Map[String,", - elementType, - "]] = Encoder.encodeMap[String, ", - elementType, - "]" - ]); - } - - protected emitTopLevelMap(t: MapType, name: Name): void { - super.emitTopLevelMap(t, name); - const elementType = this.scalaType(t.values); - this.ensureBlankLine(); - this.emitLine([ - "given (using ev : ", - elementType, - "): Encoder[Map[String, ", - elementType, - "]] = Encoder.encodeMap[String, ", - elementType, - "]" - ]); - } - - protected emitUnionDefinition(u: UnionType, unionName: Name): void { - function sortBy(t: Type): string { - const kind = t.kind; - if (kind === "class") return kind; - return "_" + kind; - } - - this.emitDescription(this.descriptionForType(u)); - - const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); - const theTypes: Sourcelike[] = []; - this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { - theTypes.push(this.scalaType(t)); - }); - if (maybeNull !== null) { - theTypes.push(this.nameForUnionMember(u, maybeNull)); - } - - this.emitItem(["type ", unionName, " = "]); - theTypes.forEach((t, i) => { - this.emitItem(i === 0 ? t : [" | ", t]); - }); - const thisUnionType = theTypes.map(x => this.sourcelikeToString(x)).join(" | "); - - this.ensureBlankLine(); - if (!this.seenUnionTypes.some(y => y === thisUnionType)) { - this.seenUnionTypes.push(thisUnionType); - const sourceLikeTypes: Array<[Sourcelike, Type]> = []; - this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { - sourceLikeTypes.push([this.scalaType(t), t]); - }); - if (maybeNull !== null) { - sourceLikeTypes.push([this.nameForUnionMember(u, maybeNull), maybeNull]); - } - - this.emitLine(["given Decoder[", unionName, "] = {"]); - this.indent(() => { - this.emitLine(["List[Decoder[", unionName, "]]("]); - this.indent(() => { - sourceLikeTypes.forEach(t => { - this.emitLine(["Decoder[", t[0], "].widen,"]); - }); - }); - this.emitLine(").reduceLeft(_ or _)"); - }); - this.emitLine(["}"]); - - this.ensureBlankLine(); - - this.emitLine(["given Encoder[", unionName, "] = Encoder.instance {"]); - this.indent(() => { - sourceLikeTypes.forEach((t, i) => { - const paramTemp = `enc${i.toString()}`; - this.emitLine([ - "case ", - paramTemp, - " : ", - t[0], - " => ", - this.circeEncoderForType(t[1], false, false, paramTemp) - ]); - }); - }); - this.emitLine("}"); - } - } -} - -export class Scala3TargetLanguage extends TargetLanguage { - public constructor() { - super("Scala3", ["scala3"], "scala"); - } - - protected getOptions(): Array> { - return [scala3Options.framework, scala3Options.packageName]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { - const options = getOptionValues(scala3Options, untypedOptionValues); - - switch (options.framework) { - case Framework.None: - return new Scala3Renderer(this, renderContext, options); - case Framework.Upickle: - return new UpickleRenderer(this, renderContext, options); - case Framework.Circe: - return new CirceRenderer(this, renderContext, options); - default: - return assertNever(options.framework); - } - } -} diff --git a/packages/quicktype-core/src/language/Scala3/CirceRenderer.ts b/packages/quicktype-core/src/language/Scala3/CirceRenderer.ts new file mode 100644 index 000000000..8be6e660d --- /dev/null +++ b/packages/quicktype-core/src/language/Scala3/CirceRenderer.ts @@ -0,0 +1,193 @@ +import { type Name } from "../../Naming"; +import { type Sourcelike } from "../../Source"; +import { type ArrayType, type ClassType, type EnumType, type MapType, type Type, type UnionType } from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { Scala3Renderer } from "./Scala3Renderer"; +import { wrapOption } from "./utils"; + +export class CirceRenderer extends Scala3Renderer { + private seenUnionTypes: string[] = []; + + protected circeEncoderForType(t: Type, __ = false, noOptional = false, paramName: string = ""): Sourcelike { + return matchType( + t, + _anyType => ["Encoder.encodeJson(", paramName, ")"], + _nullType => ["Encoder.encodeNone(", paramName, ")"], + _boolType => ["Encoder.encodeBoolean(", paramName, ")"], + _integerType => ["Encoder.encodeLong(", paramName, ")"], + _doubleType => ["Encoder.encodeDouble(", paramName, ")"], + _stringType => ["Encoder.encodeString(", paramName, ")"], + arrayType => ["Encoder.encodeSeq[", this.scalaType(arrayType.items), "].apply(", paramName, ")"], + classType => ["Encoder.AsObject[", this.scalaType(classType), "].apply(", paramName, ")"], + mapType => ["Encoder.encodeMap[String,", this.scalaType(mapType.values), "].apply(", paramName, ")"], + _ => ["Encoder.encodeString(", paramName, ")"], + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + if (noOptional) { + return ["Encoder.AsObject[", this.nameForNamedType(nullable), "]"]; + } else { + return ["Encoder.AsObject[Option[", this.nameForNamedType(nullable), "]]"]; + } + } + + return ["Encoder.AsObject[", this.nameForNamedType(unionType), "]"]; + } + ); + } + + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + this.emitDescription(this.descriptionForType(c)); + this.ensureBlankLine(); + this.emitLine("case class ", className, "() derives Encoder.AsObject, Decoder"); + } + + protected anySourceType(optional: boolean): Sourcelike { + return [wrapOption("Json", optional)]; + } + + protected emitClassDefinitionMethods(): void { + this.emitLine(") derives Encoder.AsObject, Decoder"); + } + + protected emitEnumDefinition(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + + this.ensureBlankLine(); + this.emitItem(["type ", enumName, " = "]); + let count = e.cases.size; + this.forEachEnumCase(e, "none", (_, jsonName) => { + // if (!(jsonName == "")) { + /* const backticks = + shouldAddBacktick(jsonName) || + jsonName.includes(" ") || + !isNaN(parseInt(jsonName.charAt(0))) + if (backticks) {this.emitItem("`")} else */ + this.emitItem(['"', jsonName, '"']); + // if (backticks) {this.emitItem("`")} + if (--count > 0) this.emitItem([" | "]); + // } else { + // --count + // } + }); + this.ensureBlankLine(); + } + + protected emitHeader(): void { + super.emitHeader(); + + this.emitLine("import scala.util.Try"); + this.emitLine("import io.circe.syntax._"); + this.emitLine("import io.circe._"); + this.emitLine("import cats.syntax.functor._"); + this.ensureBlankLine(); + + this.emitLine("// For serialising string unions"); + this.emitLine( + "given [A <: Singleton](using A <:< String): Decoder[A] = Decoder.decodeString.emapTry(x => Try(x.asInstanceOf[A])) " + ); + this.emitLine( + "given [A <: Singleton](using ev: A <:< String): Encoder[A] = Encoder.encodeString.contramap(ev) " + ); + this.ensureBlankLine(); + this.emitLine("// If a union has a null in, then we'll need this too... "); + this.emitLine("type NullValue = None.type"); + } + + protected emitTopLevelArray(t: ArrayType, name: Name): void { + super.emitTopLevelArray(t, name); + const elementType = this.scalaType(t.items); + this.emitLine([ + "given (using ev : ", + elementType, + "): Encoder[Map[String,", + elementType, + "]] = Encoder.encodeMap[String, ", + elementType, + "]" + ]); + } + + protected emitTopLevelMap(t: MapType, name: Name): void { + super.emitTopLevelMap(t, name); + const elementType = this.scalaType(t.values); + this.ensureBlankLine(); + this.emitLine([ + "given (using ev : ", + elementType, + "): Encoder[Map[String, ", + elementType, + "]] = Encoder.encodeMap[String, ", + elementType, + "]" + ]); + } + + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + function sortBy(t: Type): string { + const kind = t.kind; + if (kind === "class") return kind; + return "_" + kind; + } + + this.emitDescription(this.descriptionForType(u)); + + const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); + const theTypes: Sourcelike[] = []; + this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { + theTypes.push(this.scalaType(t)); + }); + if (maybeNull !== null) { + theTypes.push(this.nameForUnionMember(u, maybeNull)); + } + + this.emitItem(["type ", unionName, " = "]); + theTypes.forEach((t, i) => { + this.emitItem(i === 0 ? t : [" | ", t]); + }); + const thisUnionType = theTypes.map(x => this.sourcelikeToString(x)).join(" | "); + + this.ensureBlankLine(); + if (!this.seenUnionTypes.some(y => y === thisUnionType)) { + this.seenUnionTypes.push(thisUnionType); + const sourceLikeTypes: Array<[Sourcelike, Type]> = []; + this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { + sourceLikeTypes.push([this.scalaType(t), t]); + }); + if (maybeNull !== null) { + sourceLikeTypes.push([this.nameForUnionMember(u, maybeNull), maybeNull]); + } + + this.emitLine(["given Decoder[", unionName, "] = {"]); + this.indent(() => { + this.emitLine(["List[Decoder[", unionName, "]]("]); + this.indent(() => { + sourceLikeTypes.forEach(t => { + this.emitLine(["Decoder[", t[0], "].widen,"]); + }); + }); + this.emitLine(").reduceLeft(_ or _)"); + }); + this.emitLine(["}"]); + + this.ensureBlankLine(); + + this.emitLine(["given Encoder[", unionName, "] = Encoder.instance {"]); + this.indent(() => { + sourceLikeTypes.forEach((t, i) => { + const paramTemp = `enc${i.toString()}`; + this.emitLine([ + "case ", + paramTemp, + " : ", + t[0], + " => ", + this.circeEncoderForType(t[1], false, false, paramTemp) + ]); + }); + }); + this.emitLine("}"); + } + } +} diff --git a/packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts b/packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts new file mode 100644 index 000000000..bc5fe7a56 --- /dev/null +++ b/packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts @@ -0,0 +1,313 @@ +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + type ClassType, + type EnumType, + MapType, + type ObjectType, + type Type, + type UnionType +} from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { type scala3Options } from "./language"; +import { lowerNamingFunction, scalaNameStyle, shouldAddBacktick, upperNamingFunction, wrapOption } from "./utils"; + +export class Scala3Renderer extends ConvenienceRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + protected readonly _scalaOptions: OptionValues + ) { + super(targetLanguage, renderContext); + } + + protected forbiddenNamesForGlobalNamespace(): readonly string[] { + return keywords; + } + + protected forbiddenForObjectProperties(_: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + return { names: [], includeGlobalForbidden: true }; + } + + protected forbiddenForEnumCases(_: EnumType, _enumName: Name): ForbiddenWordsInfo { + return { names: [], includeGlobalForbidden: true }; + } + + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + return { names: [], includeGlobalForbidden: false }; + } + + protected topLevelNameStyle(rawName: string): string { + return scalaNameStyle(true, rawName); + } + + protected makeNamedTypeNamer(): Namer { + return upperNamingFunction; + } + + protected namerForObjectProperty(): Namer { + return lowerNamingFunction; + } + + protected makeUnionMemberNamer(): Namer { + return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); + } + + protected makeEnumCaseNamer(): Namer { + return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate + } + + protected emitDescriptionBlock(lines: Sourcelike[]): void { + this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + } + + protected emitBlock( + line: Sourcelike, + f: () => void, + delimiter: "curly" | "paren" | "lambda" | "none" = "curly" + ): void { + const [open, close] = + delimiter === "curly" + ? ["{", "}"] + : delimiter === "paren" + ? ["(", ")"] + : delimiter === "none" + ? ["", ""] + : ["{", "})"]; + this.emitLine(line, " ", open); + this.indent(f); + this.emitLine(close); + } + + protected anySourceType(optional: boolean): Sourcelike { + return [wrapOption("Any", optional)]; + } + + // (asarazan): I've broken out the following two functions + // because some renderers, such as kotlinx, can cope with `any`, while some get mad. + protected arrayType(arrayType: ArrayType, withIssues = false): Sourcelike { + return ["Seq[", this.scalaType(arrayType.items, withIssues), "]"]; + } + + protected mapType(mapType: MapType, withIssues = false): Sourcelike { + return ["Map[String, ", this.scalaType(mapType.values, withIssues), "]"]; + } + + protected scalaType(t: Type, withIssues = false, noOptional = false): Sourcelike { + return matchType( + t, + _anyType => { + return maybeAnnotated(withIssues, anyTypeIssueAnnotation, this.anySourceType(!noOptional)); + }, + _nullType => { + // return "None.type" + return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(!noOptional)); + }, + _boolType => "Boolean", + _integerType => "Long", + _doubleType => "Double", + _stringType => "String", + arrayType => this.arrayType(arrayType, withIssues), + classType => this.nameForNamedType(classType), + mapType => this.mapType(mapType, withIssues), + enumType => this.nameForNamedType(enumType), + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + if (noOptional) { + return [this.scalaType(nullable, withIssues)]; + } else { + return ["Option[", this.scalaType(nullable, withIssues), "]"]; + } + } + + return this.nameForNamedType(unionType); + } + ); + } + + protected emitUsageHeader(): void { + // To be overridden + } + + protected emitHeader(): void { + if (this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + } else { + this.emitUsageHeader(); + } + + this.ensureBlankLine(); + this.emitLine("package ", this._scalaOptions.packageName); + this.ensureBlankLine(); + } + + protected emitTopLevelArray(t: ArrayType, name: Name): void { + const elementType = this.scalaType(t.items); + this.emitLine(["type ", name, " = List[", elementType, "]"]); + } + + protected emitTopLevelMap(t: MapType, name: Name): void { + const elementType = this.scalaType(t.values); + this.emitLine(["type ", name, " = Map[String, ", elementType, "]"]); + } + + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + this.emitDescription(this.descriptionForType(c)); + this.emitLine("case class ", className, "()"); + } + + protected emitClassDefinition(c: ClassType, className: Name): void { + if (c.getProperties().size === 0) { + this.emitEmptyClassDefinition(c, className); + return; + } + + const scalaType = (p: ClassProperty): Sourcelike => { + if (p.isOptional) { + return ["Option[", this.scalaType(p.type, true, true), "]"]; + } else { + return this.scalaType(p.type, true); + } + }; + + this.emitDescription(this.descriptionForType(c)); + this.emitLine("case class ", className, " ("); + this.indent(() => { + let count = c.getProperties().size; + let first = true; + this.forEachClassProperty(c, "none", (_, jsonName, p) => { + const nullable = p.type.kind === "union" && nullableFromUnion(p.type as UnionType) !== null; + const nullableOrOptional = p.isOptional || p.type.kind === "null" || nullable; + const last = --count === 0; + const meta: Array<() => void> = []; + + const description = this.descriptionForClassProperty(c, jsonName); + if (description !== undefined) { + meta.push(() => this.emitDescription(description)); + } + + if (meta.length > 0 && !first) { + this.ensureBlankLine(); + } + + for (const emit of meta) { + emit(); + } + + const nameNeedsBackticks = jsonName.endsWith("_") || shouldAddBacktick(jsonName); + const nameWithBackticks = nameNeedsBackticks ? "`" + jsonName + "`" : jsonName; + this.emitLine( + "val ", + nameWithBackticks, + " : ", + scalaType(p), + p.isOptional ? " = None" : nullableOrOptional ? " = None" : "", + last ? "" : "," + ); + + if (meta.length > 0 && !last) { + this.ensureBlankLine(); + } + + first = false; + }); + }); + + this.emitClassDefinitionMethods(); + } + + protected emitClassDefinitionMethods(): void { + this.emitLine(")"); + } + + protected emitEnumDefinition(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + + this.emitBlock( + ["enum ", enumName, " : "], + () => { + let count = e.cases.size; + if (count > 0) { + this.emitItem("\t case "); + } + + this.forEachEnumCase(e, "none", (name, jsonName) => { + if (!(jsonName == "")) { + const backticks = + shouldAddBacktick(jsonName) || + jsonName.includes(" ") || + !isNaN(parseInt(jsonName.charAt(0))); + if (backticks) { + this.emitItem("`"); + } + + this.emitItemOnce([name]); + if (backticks) { + this.emitItem("`"); + } + + if (--count > 0) this.emitItem([","]); + } else { + --count; + } + }); + }, + "none" + ); + } + + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + function sortBy(t: Type): string { + const kind = t.kind; + if (kind === "class") return kind; + return "_" + kind; + } + + this.emitDescription(this.descriptionForType(u)); + + const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); + const theTypes: Sourcelike[] = []; + this.forEachUnionMember(u, nonNulls, "none", null, (_, t) => { + theTypes.push(this.scalaType(t)); + }); + if (maybeNull !== null) { + theTypes.push(this.nameForUnionMember(u, maybeNull)); + } + + this.emitItem(["type ", unionName, " = "]); + theTypes.forEach((t, i) => { + this.emitItem(i === 0 ? t : [" | ", t]); + }); + this.ensureBlankLine(); + } + + protected emitSourceStructure(): void { + this.emitHeader(); + + // Top-level arrays, maps + this.forEachTopLevel("leading", (t, name) => { + if (t instanceof ArrayType) { + this.emitTopLevelArray(t, name); + } else if (t instanceof MapType) { + this.emitTopLevelMap(t, name); + } + }); + + this.forEachNamedType( + "leading-and-interposing", + (c: ClassType, n: Name) => this.emitClassDefinition(c, n), + (e, n) => this.emitEnumDefinition(e, n), + (u, n) => this.emitUnionDefinition(u, n) + ); + } +} diff --git a/packages/quicktype-core/src/language/Scala3/UpickleRenderer.ts b/packages/quicktype-core/src/language/Scala3/UpickleRenderer.ts new file mode 100644 index 000000000..0eb5ce354 --- /dev/null +++ b/packages/quicktype-core/src/language/Scala3/UpickleRenderer.ts @@ -0,0 +1,14 @@ +import { Scala3Renderer } from "./Scala3Renderer"; + +export class UpickleRenderer extends Scala3Renderer { + protected emitClassDefinitionMethods(): void { + this.emitLine(") derives ReadWriter "); + } + + protected emitHeader(): void { + super.emitHeader(); + + this.emitLine("import upickle.default.*"); + this.ensureBlankLine(); + } +} diff --git a/packages/quicktype-core/src/language/Scala3/constants.ts b/packages/quicktype-core/src/language/Scala3/constants.ts new file mode 100644 index 000000000..b41844e78 --- /dev/null +++ b/packages/quicktype-core/src/language/Scala3/constants.ts @@ -0,0 +1,87 @@ +// Use backticks for param names with symbols +export const invalidSymbols = [ + ":", + "-", + "+", + "!", + "@", + "#", + "$", + "%", + "^", + "&", + "*", + "(", + ")", + ">", + "<", + "/", + ";", + "'", + '"', + "{", + "}", + ":", + "~", + "`", + "." +] as const; + +export const keywords = [ + "abstract", + "case", + "catch", + "class", + "def", + "do", + "else", + "enum", + "extends", + "export", + "false", + "final", + "finally", + "for", + "forSome", + "if", + "implicit", + "import", + "lazy", + "match", + "new", + "null", + "object", + "override", + "package", + "private", + "protected", + "return", + "sealed", + "super", + "this", + "then", + "throw", + "trait", + "try", + "true", + "type", + "val", + "var", + "while", + "with", + "yield", + "Any", + "Boolean", + "Double", + "Float", + "Long", + "Int", + "Short", + "System", + "Byte", + "String", + "Array", + "List", + "Map", + "Enum" +] as const; diff --git a/packages/quicktype-core/src/language/Scala3/index.ts b/packages/quicktype-core/src/language/Scala3/index.ts new file mode 100644 index 000000000..33c5960ae --- /dev/null +++ b/packages/quicktype-core/src/language/Scala3/index.ts @@ -0,0 +1,4 @@ +export { Scala3TargetLanguage, scala3Options } from "./language"; +export { Scala3Renderer } from "./Scala3Renderer"; +export { CirceRenderer } from "./CirceRenderer"; +export { UpickleRenderer } from "./UpickleRenderer"; diff --git a/packages/quicktype-core/src/language/Scala3/language.ts b/packages/quicktype-core/src/language/Scala3/language.ts new file mode 100644 index 000000000..3b00207d0 --- /dev/null +++ b/packages/quicktype-core/src/language/Scala3/language.ts @@ -0,0 +1,63 @@ +import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type RenderContext } from "../../Renderer"; +import { EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { assertNever } from "../../support/Support"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { CirceRenderer } from "./CirceRenderer"; +import { Scala3Renderer } from "./Scala3Renderer"; +import { UpickleRenderer } from "./UpickleRenderer"; + +export enum Framework { + None = "None", + Upickle = "Upickle", + Circe = "Circe" +} + +export const scala3Options = { + framework: new EnumOption( + "framework", + "Serialization framework", + [ + ["just-types", Framework.None], + ["circe", Framework.Circe], + ["upickle", Framework.Upickle] + ], + undefined + ), + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") +}; + +export class Scala3TargetLanguage extends TargetLanguage { + public constructor() { + super("Scala3", ["scala3"], "scala"); + } + + protected getOptions(): Array> { + return [scala3Options.framework, scala3Options.packageName]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { + const options = getOptionValues(scala3Options, untypedOptionValues); + + switch (options.framework) { + case Framework.None: + return new Scala3Renderer(this, renderContext, options); + case Framework.Upickle: + return new UpickleRenderer(this, renderContext, options); + case Framework.Circe: + return new CirceRenderer(this, renderContext, options); + default: + return assertNever(options.framework); + } + } +} diff --git a/packages/quicktype-core/src/language/Scala3/utils.ts b/packages/quicktype-core/src/language/Scala3/utils.ts new file mode 100644 index 000000000..40358a18e --- /dev/null +++ b/packages/quicktype-core/src/language/Scala3/utils.ts @@ -0,0 +1,72 @@ +import { funPrefixNamer } from "../../Naming"; +import { + allLowerWordStyle, + allUpperWordStyle, + combineWords, + firstUpperWordStyle, + isDigit, + isLetterOrUnderscore, + isNumeric, + legalizeCharacters, + splitIntoWords +} from "../../support/Strings"; +import { invalidSymbols, keywords } from "./constants"; + +/** + * Check if given parameter name should be wrapped in a backtick + * @param paramName + */ +export const shouldAddBacktick = (paramName: string): boolean => { + return ( + keywords.some(s => paramName === s) || + invalidSymbols.some(s => paramName.includes(s)) || + !isNaN(+parseFloat(paramName)) || + !isNaN(parseInt(paramName.charAt(0))) + ); +}; + +export const wrapOption = (s: string, optional: boolean): string => { + if (optional) { + return "Option[" + s + "]"; + } else { + return s; + } +}; + +function isPartCharacter(codePoint: number): boolean { + return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); +} + +function isStartCharacter(codePoint: number): boolean { + return isPartCharacter(codePoint) && !isDigit(codePoint); +} + +const legalizeName = legalizeCharacters(isPartCharacter); + +export function scalaNameStyle(isUpper: boolean, original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + isUpper ? firstUpperWordStyle : allLowerWordStyle, + firstUpperWordStyle, + isUpper ? allUpperWordStyle : allLowerWordStyle, + allUpperWordStyle, + "", + isStartCharacter + ); +} + +/* function unicodeEscape(codePoint: number): string { + return "\\u" + intToHex(codePoint, 4); +} */ + +//const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); + +/* function stringEscape(s: string): string { + // "$this" is a template string in Kotlin so we have to escape $ + return _stringEscape(s).replace(/\$/g, "\\$"); +} */ + +export const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s)); +export const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); From 748e45d37c116e3f34759b0f927dff2f66c7350c Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 11:52:13 -0700 Subject: [PATCH 45/80] move Rust to own dir --- .../{Rust.ts => Rust/RustRenderer.ts} | 316 ++---------------- .../src/language/Rust/constants.ts | 76 +++++ .../quicktype-core/src/language/Rust/index.ts | 2 + .../src/language/Rust/language.ts | 58 ++++ .../quicktype-core/src/language/Rust/utils.ts | 152 +++++++++ 5 files changed, 310 insertions(+), 294 deletions(-) rename packages/quicktype-core/src/language/{Rust.ts => Rust/RustRenderer.ts} (54%) create mode 100644 packages/quicktype-core/src/language/Rust/constants.ts create mode 100644 packages/quicktype-core/src/language/Rust/index.ts create mode 100644 packages/quicktype-core/src/language/Rust/language.ts create mode 100644 packages/quicktype-core/src/language/Rust/utils.ts diff --git a/packages/quicktype-core/src/language/Rust.ts b/packages/quicktype-core/src/language/Rust/RustRenderer.ts similarity index 54% rename from packages/quicktype-core/src/language/Rust.ts rename to packages/quicktype-core/src/language/Rust/RustRenderer.ts index 8dcf5b93a..79b25acea 100644 --- a/packages/quicktype-core/src/language/Rust.ts +++ b/packages/quicktype-core/src/language/Rust/RustRenderer.ts @@ -1,267 +1,28 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { mapFirst } from "collection-utils"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated } from "../Source"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { defined } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassType, type EnumType, type Type, UnionType } from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { Density, Visibility, type rustOptions } from "./language"; import { - allLowerWordStyle, - combineWords, - escapeNonPrintableMapper, - firstUpperWordStyle, - intToHex, - isAscii, - isLetterOrUnderscore, - isLetterOrUnderscoreOrDigit, - isPrintable, - legalizeCharacters, - splitIntoWords, - utf32ConcatMap -} from "../support/Strings"; -import { defined } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ClassType, type EnumType, type Type, UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export enum Density { - Normal = "Normal", - Dense = "Dense" -} - -export enum Visibility { - Private = "Private", - Crate = "Crate", - Public = "Public" -} - -export const rustOptions = { - density: new EnumOption("density", "Density", [ - ["normal", Density.Normal], - ["dense", Density.Dense] - ]), - visibility: new EnumOption("visibility", "Field visibility", [ - ["private", Visibility.Private], - ["crate", Visibility.Crate], - ["public", Visibility.Public] - ]), - deriveDebug: new BooleanOption("derive-debug", "Derive Debug impl", false), - deriveClone: new BooleanOption("derive-clone", "Derive Clone impl", false), - derivePartialEq: new BooleanOption("derive-partial-eq", "Derive PartialEq impl", false), - skipSerializingNone: new BooleanOption("skip-serializing-none", "Skip serializing empty Option fields", false), - edition2018: new BooleanOption("edition-2018", "Edition 2018", true), - leadingComments: new BooleanOption("leading-comments", "Leading Comments", true) -}; - -type NameToParts = (name: string) => string[]; -type PartsToName = (parts: string[]) => string; -interface NamingStyle { - fromParts: PartsToName; - regex: RegExp; - toParts: NameToParts; -} - -const namingStyles: Record = { - snake_case: { - regex: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/, - toParts: (name: string): string[] => name.split("_"), - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("_") - }, - SCREAMING_SNAKE_CASE: { - regex: /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/, - toParts: (name: string): string[] => name.split("_"), - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("_") - }, - camelCase: { - regex: /^[a-z]+([A-Z0-9][a-z]*)*$/, - toParts: (name: string): string[] => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")), - fromParts: (parts: string[]): string => - parts - .map((p, i) => - i === 0 ? p.toLowerCase() : p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase() - ) - .join("") - }, - PascalCase: { - regex: /^[A-Z][a-z]*([A-Z0-9][a-z]*)*$/, - toParts: (name: string): string[] => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")), - fromParts: (parts: string[]): string => - parts.map(p => p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase()).join("") - }, - "kebab-case": { - regex: /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/, - toParts: (name: string): string[] => name.split("-"), - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("-") - }, - "SCREAMING-KEBAB-CASE": { - regex: /^[A-Z][A-Z0-9]*(-[A-Z0-9]+)*$/, - toParts: (name: string): string[] => name.split("-"), - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("-") - }, - lowercase: { - regex: /^[a-z][a-z0-9]*$/, - toParts: (name: string): string[] => [name], - fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("") - }, - UPPERCASE: { - regex: /^[A-Z][A-Z0-9]*$/, - toParts: (name: string): string[] => [name], - fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("") - } -}; - -export class RustTargetLanguage extends TargetLanguage { - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): RustRenderer { - return new RustRenderer(this, renderContext, getOptionValues(rustOptions, untypedOptionValues)); - } - - public constructor() { - super("Rust", ["rust", "rs", "rustlang"], "rs"); - } - - protected getOptions(): Array> { - return [ - rustOptions.density, - rustOptions.visibility, - rustOptions.deriveDebug, - rustOptions.deriveClone, - rustOptions.derivePartialEq, - rustOptions.edition2018, - rustOptions.leadingComments, - rustOptions.skipSerializingNone - ]; - } -} - -const keywords = [ - "Serialize", - "Deserialize", - - // Special reserved identifiers used internally for elided lifetimes, - // unnamed method parameters, crate root module, error recovery etc. - "{{root}}", - "$crate", - - // Keywords used in the language. - "as", - "async", - "box", - "break", - "const", - "continue", - "crate", - "else", - "enum", - "extern", - "false", - "fn", - "for", - "if", - "impl", - "in", - "let", - "loop", - "match", - "mod", - "move", - "mut", - "pub", - "ref", - "return", - "self", - "Self", - "static", - "struct", - "super", - "trait", - "true", - "type", - "unsafe", - "use", - "where", - "while", - - // Keywords reserved for future use. - "abstract", - "alignof", - "become", - "do", - "final", - "macro", - "offsetof", - "override", - "priv", - "proc", - "pure", - "sizeof", - "typeof", - "unsized", - "virtual", - "yield", - - // Weak keywords, have special meaning only in specific contexts. - "catch", - "default", - "dyn", - "'static", - "union", - - // Conflict between `std::Option` and potentially generated Option - "option" -]; - -const isAsciiLetterOrUnderscoreOrDigit = (codePoint: number): boolean => { - if (!isAscii(codePoint)) { - return false; - } - - return isLetterOrUnderscoreOrDigit(codePoint); -}; - -const isAsciiLetterOrUnderscore = (codePoint: number): boolean => { - if (!isAscii(codePoint)) { - return false; - } - - return isLetterOrUnderscore(codePoint); -}; - -const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); - -function rustStyle(original: string, isSnakeCase: boolean): string { - const words = splitIntoWords(original); - - const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; - - const combined = combineWords( - words, - legalizeName, - wordStyle, - wordStyle, - wordStyle, - wordStyle, - isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore - ); - - return combined === "_" ? "_underscore" : combined; -} - -const snakeNamingFunction = funPrefixNamer("default", (original: string) => rustStyle(original, true)); -const camelNamingFunction = funPrefixNamer("camel", (original: string) => rustStyle(original, false)); - -const standardUnicodeRustEscape = (codePoint: number): string => { - if (codePoint <= 0xffff) { - return "\\u{" + intToHex(codePoint, 4) + "}"; - } else { - return "\\u{" + intToHex(codePoint, 6) + "}"; - } -}; - -const rustStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeRustEscape)); + camelNamingFunction, + getPreferedNamingStyle, + listMatchingNamingStyles, + nameToNamingStyle, + namingStyles, + rustStringEscape, + snakeNamingFunction +} from "./utils"; export class RustRenderer extends ConvenienceRenderer { public constructor( @@ -288,7 +49,7 @@ export class RustRenderer extends ConvenienceRenderer { return camelNamingFunction; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return keywords; } @@ -548,36 +309,3 @@ export class RustRenderer extends ConvenienceRenderer { ); } } - -function getPreferedNamingStyle(namingStyleOccurences: string[], defaultStyle: string): string { - const occurrences = Object.fromEntries(Object.keys(namingStyles).map(key => [key, 0])); - namingStyleOccurences.forEach(style => ++occurrences[style]); - const max = Math.max(...Object.values(occurrences)); - const preferedStyles = Object.entries(occurrences) - .filter(([_style, num]) => num === max) - .map(([style, _num]) => style); - if (preferedStyles.includes(defaultStyle)) { - return defaultStyle; - } - - return preferedStyles[0]; -} - -function listMatchingNamingStyles(name: string): string[] { - return Object.entries(namingStyles) - .filter(([_, { regex }]) => regex.test(name)) - .map(([namingStyle, _]) => namingStyle); -} - -function nameToNamingStyle(name: string, style: string): string { - if (namingStyles[style].regex.test(name)) { - return name; - } - - const fromStyle = listMatchingNamingStyles(name)[0]; - if (fromStyle === undefined) { - return name; - } - - return namingStyles[style].fromParts(namingStyles[fromStyle].toParts(name)); -} diff --git a/packages/quicktype-core/src/language/Rust/constants.ts b/packages/quicktype-core/src/language/Rust/constants.ts new file mode 100644 index 000000000..8ba3d3eb8 --- /dev/null +++ b/packages/quicktype-core/src/language/Rust/constants.ts @@ -0,0 +1,76 @@ +export const keywords = [ + "Serialize", + "Deserialize", + + // Special reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. + "{{root}}", + "$crate", + + // Keywords used in the language. + "as", + "async", + "box", + "break", + "const", + "continue", + "crate", + "else", + "enum", + "extern", + "false", + "fn", + "for", + "if", + "impl", + "in", + "let", + "loop", + "match", + "mod", + "move", + "mut", + "pub", + "ref", + "return", + "self", + "Self", + "static", + "struct", + "super", + "trait", + "true", + "type", + "unsafe", + "use", + "where", + "while", + + // Keywords reserved for future use. + "abstract", + "alignof", + "become", + "do", + "final", + "macro", + "offsetof", + "override", + "priv", + "proc", + "pure", + "sizeof", + "typeof", + "unsized", + "virtual", + "yield", + + // Weak keywords, have special meaning only in specific contexts. + "catch", + "default", + "dyn", + "'static", + "union", + + // Conflict between `std::Option` and potentially generated Option + "option" +] as const; diff --git a/packages/quicktype-core/src/language/Rust/index.ts b/packages/quicktype-core/src/language/Rust/index.ts new file mode 100644 index 000000000..456ae1274 --- /dev/null +++ b/packages/quicktype-core/src/language/Rust/index.ts @@ -0,0 +1,2 @@ +export { RustTargetLanguage, rustOptions } from "./language"; +export { RustRenderer } from "./RustRenderer"; diff --git a/packages/quicktype-core/src/language/Rust/language.ts b/packages/quicktype-core/src/language/Rust/language.ts new file mode 100644 index 000000000..0c206884e --- /dev/null +++ b/packages/quicktype-core/src/language/Rust/language.ts @@ -0,0 +1,58 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { RustRenderer } from "./RustRenderer"; + +export enum Density { + Normal = "Normal", + Dense = "Dense" +} + +export enum Visibility { + Private = "Private", + Crate = "Crate", + Public = "Public" +} + +export const rustOptions = { + density: new EnumOption("density", "Density", [ + ["normal", Density.Normal], + ["dense", Density.Dense] + ]), + visibility: new EnumOption("visibility", "Field visibility", [ + ["private", Visibility.Private], + ["crate", Visibility.Crate], + ["public", Visibility.Public] + ]), + deriveDebug: new BooleanOption("derive-debug", "Derive Debug impl", false), + deriveClone: new BooleanOption("derive-clone", "Derive Clone impl", false), + derivePartialEq: new BooleanOption("derive-partial-eq", "Derive PartialEq impl", false), + skipSerializingNone: new BooleanOption("skip-serializing-none", "Skip serializing empty Option fields", false), + edition2018: new BooleanOption("edition-2018", "Edition 2018", true), + leadingComments: new BooleanOption("leading-comments", "Leading Comments", true) +}; + +export class RustTargetLanguage extends TargetLanguage { + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): RustRenderer { + return new RustRenderer(this, renderContext, getOptionValues(rustOptions, untypedOptionValues)); + } + + public constructor() { + super("Rust", ["rust", "rs", "rustlang"], "rs"); + } + + protected getOptions(): Array> { + return [ + rustOptions.density, + rustOptions.visibility, + rustOptions.deriveDebug, + rustOptions.deriveClone, + rustOptions.derivePartialEq, + rustOptions.edition2018, + rustOptions.leadingComments, + rustOptions.skipSerializingNone + ]; + } +} diff --git a/packages/quicktype-core/src/language/Rust/utils.ts b/packages/quicktype-core/src/language/Rust/utils.ts new file mode 100644 index 000000000..4da4582cf --- /dev/null +++ b/packages/quicktype-core/src/language/Rust/utils.ts @@ -0,0 +1,152 @@ +import { + legalizeCharacters, + splitIntoWords, + isLetterOrUnderscoreOrDigit, + combineWords, + allLowerWordStyle, + firstUpperWordStyle, + intToHex, + utf32ConcatMap, + escapeNonPrintableMapper, + isPrintable, + isAscii, + isLetterOrUnderscore +} from "../../support/Strings"; +import { funPrefixNamer } from "../../Naming"; + +type NameToParts = (name: string) => string[]; +type PartsToName = (parts: string[]) => string; +type NamingStyle = { + regex: RegExp; + toParts: NameToParts; + fromParts: PartsToName; +}; + +export const namingStyles: Record = { + snake_case: { + regex: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/, + toParts: (name: string): string[] => name.split("_"), + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("_") + }, + SCREAMING_SNAKE_CASE: { + regex: /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/, + toParts: (name: string): string[] => name.split("_"), + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("_") + }, + camelCase: { + regex: /^[a-z]+([A-Z0-9][a-z]*)*$/, + toParts: (name: string): string[] => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")), + fromParts: (parts: string[]): string => + parts + .map((p, i) => + i === 0 ? p.toLowerCase() : p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase() + ) + .join("") + }, + PascalCase: { + regex: /^[A-Z][a-z]*([A-Z0-9][a-z]*)*$/, + toParts: (name: string): string[] => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")), + fromParts: (parts: string[]): string => + parts.map(p => p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase()).join("") + }, + "kebab-case": { + regex: /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/, + toParts: (name: string): string[] => name.split("-"), + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("-") + }, + "SCREAMING-KEBAB-CASE": { + regex: /^[A-Z][A-Z0-9]*(-[A-Z0-9]+)*$/, + toParts: (name: string): string[] => name.split("-"), + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("-") + }, + lowercase: { + regex: /^[a-z][a-z0-9]*$/, + toParts: (name: string): string[] => [name], + fromParts: (parts: string[]): string => parts.map(p => p.toLowerCase()).join("") + }, + UPPERCASE: { + regex: /^[A-Z][A-Z0-9]*$/, + toParts: (name: string): string[] => [name], + fromParts: (parts: string[]): string => parts.map(p => p.toUpperCase()).join("") + } +}; + +const isAsciiLetterOrUnderscoreOrDigit = (codePoint: number): boolean => { + if (!isAscii(codePoint)) { + return false; + } + + return isLetterOrUnderscoreOrDigit(codePoint); +}; + +const isAsciiLetterOrUnderscore = (codePoint: number): boolean => { + if (!isAscii(codePoint)) { + return false; + } + + return isLetterOrUnderscore(codePoint); +}; + +const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); + +function rustStyle(original: string, isSnakeCase: boolean): string { + const words = splitIntoWords(original); + + const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; + + const combined = combineWords( + words, + legalizeName, + wordStyle, + wordStyle, + wordStyle, + wordStyle, + isSnakeCase ? "_" : "", + isAsciiLetterOrUnderscore + ); + + return combined === "_" ? "_underscore" : combined; +} + +export const snakeNamingFunction = funPrefixNamer("default", (original: string) => rustStyle(original, true)); +export const camelNamingFunction = funPrefixNamer("camel", (original: string) => rustStyle(original, false)); + +const standardUnicodeRustEscape = (codePoint: number): string => { + if (codePoint <= 0xffff) { + return "\\u{" + intToHex(codePoint, 4) + "}"; + } else { + return "\\u{" + intToHex(codePoint, 6) + "}"; + } +}; + +export const rustStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeRustEscape)); + +export function getPreferedNamingStyle(namingStyleOccurences: string[], defaultStyle: string): string { + const occurrences = Object.fromEntries(Object.keys(namingStyles).map(key => [key, 0])); + namingStyleOccurences.forEach(style => ++occurrences[style]); + const max = Math.max(...Object.values(occurrences)); + const preferedStyles = Object.entries(occurrences) + .filter(([_style, num]) => num === max) + .map(([style, _num]) => style); + if (preferedStyles.includes(defaultStyle)) { + return defaultStyle; + } + return preferedStyles[0]; +} + +export function listMatchingNamingStyles(name: string): string[] { + return Object.entries(namingStyles) + .filter(([_, { regex }]) => regex.test(name)) + .map(([namingStyle, _]) => namingStyle); +} + +export function nameToNamingStyle(name: string, style: string): string { + if (namingStyles[style].regex.test(name)) { + return name; + } + const fromStyle = listMatchingNamingStyles(name)[0]; + if (fromStyle === undefined) { + return name; + } + return namingStyles[style].fromParts(namingStyles[fromStyle].toParts(name)); +} From 5d2768ea0b3233ea2f9e7b3d9aa22dea1487c5ed Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 11:58:06 -0700 Subject: [PATCH 46/80] split Ruby into new structure --- .../src/language/Ruby/RubyRenderer.ts | 630 +++++++++++++++ .../Ruby/{keywords.ts => constants.ts} | 18 +- .../quicktype-core/src/language/Ruby/index.ts | 740 +----------------- .../src/language/Ruby/language.ts | 44 ++ .../quicktype-core/src/language/Ruby/utils.ts | 64 ++ 5 files changed, 749 insertions(+), 747 deletions(-) create mode 100644 packages/quicktype-core/src/language/Ruby/RubyRenderer.ts rename packages/quicktype-core/src/language/Ruby/{keywords.ts => constants.ts} (97%) create mode 100644 packages/quicktype-core/src/language/Ruby/language.ts create mode 100644 packages/quicktype-core/src/language/Ruby/utils.ts diff --git a/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts new file mode 100644 index 000000000..bae528255 --- /dev/null +++ b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts @@ -0,0 +1,630 @@ +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { snakeCase, stringEscape } from "../../support/Strings"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + ClassType, + type EnumType, + MapType, + type Type, + type UnionType +} from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { globals } from "./constants"; +import { Strictness, type rubyOptions } from "./language"; +import { forbiddenForObjectProperties, memberNameStyle, simpleNameStyle } from "./utils"; + +export class RubyRenderer extends ConvenienceRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + private readonly _options: OptionValues + ) { + super(targetLanguage, renderContext); + } + + protected get commentLineStart(): string { + return "# "; + } + + protected get needsTypeDeclarationBeforeUse(): boolean { + return true; + } + + protected canBeForwardDeclared(t: Type): boolean { + return "class" === t.kind; + } + + protected forbiddenNamesForGlobalNamespace(): readonly string[] { + return [...globals, "Types", "JSON", "Dry", "Constructor", "Self"] as const; + } + + protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { + return { names: forbiddenForObjectProperties, includeGlobalForbidden: true }; + } + + protected makeNamedTypeNamer(): Namer { + return new Namer("types", n => simpleNameStyle(n, true), []); + } + + protected namerForObjectProperty(): Namer { + return new Namer("properties", memberNameStyle, []); + } + + protected makeUnionMemberNamer(): Namer { + return new Namer("properties", memberNameStyle, []); + } + + protected makeEnumCaseNamer(): Namer { + return new Namer("enum-cases", n => simpleNameStyle(n, true), []); + } + + private dryType(t: Type, isOptional = false): Sourcelike { + const optional = isOptional ? ".optional" : ""; + return matchType( + t, + _anyType => ["Types::Any", optional], + _nullType => ["Types::Nil", optional], + _boolType => ["Types::Bool", optional], + _integerType => ["Types::Integer", optional], + _doubleType => ["Types::Double", optional], + _stringType => ["Types::String", optional], + arrayType => ["Types.Array(", this.dryType(arrayType.items), ")", optional], + classType => [this.nameForNamedType(classType), optional], + mapType => ["Types::Hash.meta(of: ", this.dryType(mapType.values), ")", optional], + enumType => ["Types::", this.nameForNamedType(enumType), optional], + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + return [this.dryType(nullable), ".optional"]; + } + + return ["Types.Instance(", this.nameForNamedType(unionType), ")", optional]; + } + ); + } + + private exampleUse(t: Type, exp: Sourcelike, depth = 6, optional = false): Sourcelike { + if (depth-- <= 0) { + return exp; + } + + const safeNav = optional ? "&" : ""; + + return matchType( + t, + _anyType => exp, + _nullType => [exp, ".nil?"], + _boolType => exp, + _integerType => [exp, ".even?"], + _doubleType => exp, + _stringType => exp, + arrayType => this.exampleUse(arrayType.items, [exp, safeNav, ".first"], depth), + classType => { + let info: { name: Name; prop: ClassProperty } | undefined; + this.forEachClassProperty(classType, "none", (name, _json, prop) => { + if (["class", "map", "array"].includes(prop.type.kind)) { + info = { name, prop }; + } else if (info === undefined) { + info = { name, prop }; + } + }); + if (info !== undefined) { + return this.exampleUse(info.prop.type, [exp, safeNav, ".", info.name], depth, info.prop.isOptional); + } + + return exp; + }, + mapType => this.exampleUse(mapType.values, [exp, safeNav, '["…"]'], depth), + enumType => { + let name: Name | undefined; + // FIXME: This is a terrible way to get the first enum case name. + this.forEachEnumCase(enumType, "none", theName => { + if (name === undefined) { + name = theName; + } + }); + if (name !== undefined) { + return [exp, " == ", this.nameForNamedType(enumType), "::", name]; + } + + return exp; + }, + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + if (["class", "map", "array"].includes(nullable.kind)) { + return this.exampleUse(nullable, exp, depth, true); + } + + return [exp, ".nil?"]; + } + + return exp; + } + ); + } + + private jsonSample(t: Type): Sourcelike { + function inner(): string { + if (t instanceof ArrayType) { + return "[…]"; + } else if (t instanceof MapType) { + return "{…}"; + } else if (t instanceof ClassType) { + return "{…}"; + } else { + return "…"; + } + } + + return `"${inner()}"`; + } + + private fromDynamic(t: Type, e: Sourcelike, optional = false, castPrimitives = false): Sourcelike { + const primitiveCast = [this.dryType(t, optional), "[", e, "]"]; + const primitive = castPrimitives ? primitiveCast : e; + const safeAccess = optional ? "&" : ""; + return matchType( + t, + _anyType => primitive, + _nullType => primitive, + _boolType => primitive, + _integerType => primitive, + _doubleType => primitive, + _stringType => primitive, + arrayType => [e, safeAccess, ".map { |x| ", this.fromDynamic(arrayType.items, "x", false, true), " }"], + classType => { + const expression = [this.nameForNamedType(classType), ".from_dynamic!(", e, ")"]; + return optional ? [e, " ? ", expression, " : nil"] : expression; + }, + mapType => [ + ["Types::Hash", optional ? ".optional" : "", "[", e, "]"], + safeAccess, + ".map { |k, v| [k, ", + this.fromDynamic(mapType.values, "v", false, true), + "] }", + safeAccess, + ".to_h" + ], + enumType => { + const expression = ["Types::", this.nameForNamedType(enumType), "[", e, "]"]; + return optional ? [e, ".nil? ? nil : ", expression] : expression; + }, + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + return this.fromDynamic(nullable, e, true); + } + + const expression = [this.nameForNamedType(unionType), ".from_dynamic!(", e, ")"]; + return optional ? [e, " ? ", expression, " : nil"] : expression; + } + ); + } + + private toDynamic(t: Type, e: Sourcelike, optional = false): Sourcelike { + if (this.marshalsImplicitlyToDynamic(t)) { + return e; + } + + return matchType( + t, + _anyType => e, + _nullType => e, + _boolType => e, + _integerType => e, + _doubleType => e, + _stringType => e, + arrayType => [e, optional ? "&" : "", ".map { |x| ", this.toDynamic(arrayType.items, "x"), " }"], + _classType => [e, optional ? "&" : "", ".to_dynamic"], + mapType => [e, optional ? "&" : "", ".map { |k, v| [k, ", this.toDynamic(mapType.values, "v"), "] }.to_h"], + _enumType => e, + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + return this.toDynamic(nullable, e, true); + } + + if (this.marshalsImplicitlyToDynamic(unionType)) { + return e; + } + + return [e, optional ? "&" : "", ".to_dynamic"]; + } + ); + } + + private marshalsImplicitlyToDynamic(t: Type): boolean { + return matchType( + t, + _anyType => true, + _nullType => true, + _boolType => true, + _integerType => true, + _doubleType => true, + _stringType => true, + arrayType => this.marshalsImplicitlyToDynamic(arrayType.items), + _classType => false, + mapType => this.marshalsImplicitlyToDynamic(mapType.values), + _enumType => true, + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + return this.marshalsImplicitlyToDynamic(nullable); + } + + return false; + } + ); + } + + // This is only to be used to allow class properties to possibly + // marshal implicitly. They are allowed to do this because they will + // be checked in Dry::Struct.new + private propertyTypeMarshalsImplicitlyFromDynamic(t: Type): boolean { + return matchType( + t, + _anyType => true, + _nullType => true, + _boolType => true, + _integerType => true, + _doubleType => true, + _stringType => true, + arrayType => this.propertyTypeMarshalsImplicitlyFromDynamic(arrayType.items), + _classType => false, + // Map properties must be checked because Dry:Types doesn't have a generic Map + _mapType => false, + _enumType => true, + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) { + return this.propertyTypeMarshalsImplicitlyFromDynamic(nullable); + } + + return false; + } + ); + } + + private emitBlock(source: Sourcelike, emit: () => void): void { + this.emitLine(source); + this.indent(emit); + this.emitLine("end"); + } + + private emitModule(emit: () => void): void { + const emitModuleInner = (moduleName: string): void => { + const [firstModule, ...subModules] = moduleName.split("::"); + if (subModules.length > 0) { + this.emitBlock(["module ", firstModule], () => { + emitModuleInner(subModules.join("::")); + }); + } else { + this.emitBlock(["module ", moduleName], emit); + } + }; + + if (this._options.namespace !== undefined && this._options.namespace !== "") { + emitModuleInner(this._options.namespace); + } else { + emit(); + } + } + + private emitClass(c: ClassType, className: Name): void { + this.emitDescription(this.descriptionForType(c)); + this.emitBlock(["class ", className, " < Dry::Struct"], () => { + let table: Sourcelike[][] = []; + let count = c.getProperties().size; + this.forEachClassProperty(c, "none", (name, jsonName, p) => { + const last = --count === 0; + const description = this.descriptionForClassProperty(c, jsonName); + const attribute = [ + ["attribute :", name, ","], + [" ", this.dryType(p.type), p.isOptional ? ".optional" : ""] + ]; + if (description !== undefined) { + if (table.length > 0) { + this.emitTable(table); + table = []; + } + + this.ensureBlankLine(); + this.emitDescriptionBlock(description); + this.emitLine(attribute); + if (!last) { + this.ensureBlankLine(); + } + } else { + table.push(attribute); + } + }); + if (table.length > 0) { + this.emitTable(table); + } + + if (this._options.justTypes) { + return; + } + + this.ensureBlankLine(); + this.emitBlock(["def self.from_dynamic!(d)"], () => { + this.emitLine("d = Types::Hash[d]"); + this.emitLine("new("); + this.indent(() => { + const inits: Sourcelike[][] = []; + this.forEachClassProperty(c, "none", (name, jsonName, p) => { + const dynamic = p.isOptional + ? // If key is not found in hash, this will be nil + `d["${stringEscape(jsonName)}"]` + : // This will raise a runtime error if the key is not found in the hash + `d.fetch("${stringEscape(jsonName)}")`; + + if (this.propertyTypeMarshalsImplicitlyFromDynamic(p.type)) { + inits.push([ + [name, ": "], + [dynamic, ","] + ]); + } else { + const expression = this.fromDynamic(p.type, dynamic, p.isOptional); + inits.push([ + [name, ": "], + [expression, ","] + ]); + } + }); + this.emitTable(inits); + }); + this.emitLine(")"); + }); + + this.ensureBlankLine(); + this.emitBlock("def self.from_json!(json)", () => { + this.emitLine("from_dynamic!(JSON.parse(json))"); + }); + + this.ensureBlankLine(); + this.emitBlock(["def to_dynamic"], () => { + this.emitLine("{"); + this.indent(() => { + const inits: Sourcelike[][] = []; + this.forEachClassProperty(c, "none", (name, jsonName, p) => { + const expression = this.toDynamic(p.type, name, p.isOptional); + inits.push([[`"${stringEscape(jsonName)}"`], [" => ", expression, ","]]); + }); + this.emitTable(inits); + }); + this.emitLine("}"); + }); + this.ensureBlankLine(); + this.emitBlock("def to_json(options = nil)", () => { + this.emitLine("JSON.generate(to_dynamic, options)"); + }); + }); + } + + private emitEnum(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + this.emitBlock(["module ", enumName], () => { + const table: Sourcelike[][] = []; + this.forEachEnumCase(e, "none", (name, json) => { + table.push([[name], [` = "${stringEscape(json)}"`]]); + }); + this.emitTable(table); + }); + } + + private emitUnion(u: UnionType, unionName: Name): void { + this.emitDescription(this.descriptionForType(u)); + this.emitBlock(["class ", unionName, " < Dry::Struct"], () => { + const table: Sourcelike[][] = []; + this.forEachUnionMember(u, u.getChildren(), "none", null, (name, t) => { + table.push([["attribute :", name, ", "], [this.dryType(t, true)]]); + }); + this.emitTable(table); + + if (this._options.justTypes) { + return; + } + + this.ensureBlankLine(); + const [maybeNull, nonNulls] = removeNullFromUnion(u, false); + this.emitBlock("def self.from_dynamic!(d)", () => { + const memberNames = Array.from(u.getChildren()).map(member => this.nameForUnionMember(u, member)); + this.forEachUnionMember(u, u.getChildren(), "none", null, (name, t) => { + const nilMembers = memberNames + .filter(n => n !== name) + .map(memberName => [", ", memberName, ": nil"]); + if (this.propertyTypeMarshalsImplicitlyFromDynamic(t)) { + this.emitBlock(["if schema[:", name, "].right.valid? d"], () => { + this.emitLine("return new(", name, ": d", nilMembers, ")"); + }); + } else { + this.emitLine("begin"); + this.indent(() => { + this.emitLine("value = ", this.fromDynamic(t, "d")); + this.emitBlock(["if schema[:", name, "].right.valid? value"], () => { + this.emitLine("return new(", name, ": value", nilMembers, ")"); + }); + }); + this.emitLine("rescue"); + this.emitLine("end"); + } + }); + this.emitLine('raise "Invalid union"'); + }); + + this.ensureBlankLine(); + this.emitBlock("def self.from_json!(json)", () => { + this.emitLine("from_dynamic!(JSON.parse(json))"); + }); + + this.ensureBlankLine(); + this.emitBlock("def to_dynamic", () => { + let first = true; + this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { + this.emitLine(first ? "if" : "elsif", " ", name, " != nil"); + this.indent(() => { + this.emitLine(this.toDynamic(t, name)); + }); + first = false; + }); + if (maybeNull !== null) { + this.emitLine("else"); + this.indent(() => { + this.emitLine("nil"); + }); + } + + this.emitLine("end"); + }); + + this.ensureBlankLine(); + this.emitBlock("def to_json(options = nil)", () => { + this.emitLine("JSON.generate(to_dynamic, options)"); + }); + }); + } + + private emitTypesModule(): void { + this.emitBlock(["module Types"], () => { + this.emitLine("include Dry.Types(default: :nominal)"); + + const declarations: Sourcelike[][] = []; + + if (this._options.strictness !== Strictness.None) { + let has = { int: false, nil: false, bool: false, hash: false, string: false, double: false }; + this.forEachType(t => { + has = { + int: has.int || t.kind === "integer", + nil: has.nil || t.kind === "null", + bool: has.bool || t.kind === "bool", + hash: has.hash || t.kind === "map" || t.kind === "class", + string: has.string || t.kind === "string" || t.kind === "enum", + double: has.double || t.kind === "double" + }; + }); + if (has.int) declarations.push([["Integer"], [` = ${this._options.strictness}Integer`]]); + if (this._options.strictness === Strictness.Strict) { + if (has.nil) declarations.push([["Nil"], [` = ${this._options.strictness}Nil`]]); + } + + if (has.bool) declarations.push([["Bool"], [` = ${this._options.strictness}Bool`]]); + if (has.hash) declarations.push([["Hash"], [` = ${this._options.strictness}Hash`]]); + if (has.string) declarations.push([["String"], [` = ${this._options.strictness}String`]]); + if (has.double) + declarations.push([ + ["Double"], + [` = ${this._options.strictness}Float | ${this._options.strictness}Integer`] + ]); + } + + this.forEachEnum("none", (enumType, enumName) => { + const cases: Sourcelike[][] = []; + this.forEachEnumCase(enumType, "none", (_name, json) => { + cases.push([cases.length === 0 ? "" : ", ", `"${stringEscape(json)}"`]); + }); + declarations.push([[enumName], [" = ", this._options.strictness, "String.enum(", ...cases, ")"]]); + }); + + if (declarations.length > 0) { + this.ensureBlankLine(); + this.emitTable(declarations); + } + }); + } + + protected emitSourceStructure(): void { + if (this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + } else if (!this._options.justTypes) { + this.emitLine("# This code may look unusually verbose for Ruby (and it is), but"); + this.emitLine("# it performs some subtle and complex validation of JSON data."); + this.emitLine("#"); + this.emitLine("# To parse this JSON, add 'dry-struct' and 'dry-types' gems, then do:"); + this.emitLine("#"); + this.forEachTopLevel("none", (topLevel, name) => { + const variable = modifySource(snakeCase, name); + this.emitLine("# ", variable, " = ", name, ".from_json! ", this.jsonSample(topLevel)); + this.emitLine("# puts ", this.exampleUse(topLevel, variable)); + this.emitLine("#"); + }); + this.emitLine("# If from_json! succeeds, the value returned matches the schema."); + } + + this.ensureBlankLine(); + + this.emitLine("require 'json'"); + this.emitLine("require 'dry-types'"); + this.emitLine("require 'dry-struct'"); + + this.ensureBlankLine(); + + this.emitModule(() => { + this.emitTypesModule(); + + this.forEachDeclaration("leading-and-interposing", decl => { + if (decl.kind === "forward") { + this.emitCommentLines(["(forward declaration)"]); + this.emitModule(() => { + this.emitLine("class ", this.nameForNamedType(decl.type), " < Dry::Struct; end"); + }); + } + }); + + this.forEachNamedType( + "leading-and-interposing", + (c: ClassType, n: Name) => this.emitClass(c, n), + (e, n) => this.emitEnum(e, n), + (u, n) => this.emitUnion(u, n) + ); + + if (!this._options.justTypes) { + this.forEachTopLevel( + "leading-and-interposing", + (topLevel, name) => { + const self = modifySource(snakeCase, name); + + // The json gem defines to_json on maps and primitives, so we only need to supply + // it for arrays. + const needsToJsonDefined = "array" === topLevel.kind; + + const classDeclaration = (): void => { + this.emitBlock(["class ", name], () => { + this.emitBlock(["def self.from_json!(json)"], () => { + if (needsToJsonDefined) { + this.emitLine( + self, + " = ", + this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") + ); + this.emitBlock([self, ".define_singleton_method(:to_json) do"], () => { + this.emitLine("JSON.generate(", this.toDynamic(topLevel, "self"), ")"); + }); + this.emitLine(self); + } else { + this.emitLine( + this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") + ); + } + }); + }); + }; + + this.emitModule(() => { + classDeclaration(); + }); + }, + t => this.namedTypeToNameForTopLevel(t) === undefined + ); + } + }); + } +} diff --git a/packages/quicktype-core/src/language/Ruby/keywords.ts b/packages/quicktype-core/src/language/Ruby/constants.ts similarity index 97% rename from packages/quicktype-core/src/language/Ruby/keywords.ts rename to packages/quicktype-core/src/language/Ruby/constants.ts index 0229d9044..9848048f5 100644 --- a/packages/quicktype-core/src/language/Ruby/keywords.ts +++ b/packages/quicktype-core/src/language/Ruby/constants.ts @@ -39,8 +39,8 @@ export const keywords = [ "until", "when", "while", - "yield", -]; + "yield" +] as const; const globalClasses = [ "ArgumentError", @@ -133,8 +133,8 @@ const globalClasses = [ "Undefined", "UnicodeNormalize", "Warning", - "ZeroDivisionError", -]; + "ZeroDivisionError" +] as const; const kernel = [ "__callee__", @@ -286,10 +286,10 @@ const kernel = [ "untrace_var", "untrust", "untrusted?", - "warn", -]; + "warn" +] as const; -export const globals = kernel.concat(globalClasses); +export const globals = [...kernel, ...globalClasses] as const; export const reservedProperties = [ "__id__", @@ -355,5 +355,5 @@ export const reservedProperties = [ "undef", "untrust", "while", - "with", -]; + "with" +] as const; diff --git a/packages/quicktype-core/src/language/Ruby/index.ts b/packages/quicktype-core/src/language/Ruby/index.ts index 42466baba..13ba45f36 100644 --- a/packages/quicktype-core/src/language/Ruby/index.ts +++ b/packages/quicktype-core/src/language/Ruby/index.ts @@ -1,738 +1,2 @@ -import * as unicode from "unicode-properties"; - -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; -import { type Name, Namer } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { - BooleanOption, - EnumOption, - type Option, - type OptionValues, - StringOption, - getOptionValues -} from "../../RendererOptions"; -import { type Sourcelike, modifySource } from "../../Source"; -import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - escapeNonPrintableMapper, - firstUpperWordStyle, - intToHex, - isLetterOrUnderscore, - isPrintable, - legalizeCharacters, - snakeCase, - splitIntoWords, - utf32ConcatMap -} from "../../support/Strings"; -import { TargetLanguage } from "../../TargetLanguage"; -import { - ArrayType, - type ClassProperty, - ClassType, - type EnumType, - MapType, - type Type, - type UnionType -} from "../../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; - -import * as keywords from "./keywords"; - -const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); - -function unicodeEscape(codePoint: number): string { - return "\\u{" + intToHex(codePoint, 0) + "}"; -} - -const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); - -export enum Strictness { - Coercible = "Coercible::", - None = "Types::", - Strict = "Strict::" -} - -export const rubyOptions = { - justTypes: new BooleanOption("just-types", "Plain types only", false), - strictness: new EnumOption("strictness", "Type strictness", [ - ["strict", Strictness.Strict], - ["coercible", Strictness.Coercible], - ["none", Strictness.None] - ]), - namespace: new StringOption("namespace", "Specify a wrapping Namespace", "NAME", "", "secondary") -}; - -export class RubyTargetLanguage extends TargetLanguage { - public constructor() { - super("Ruby", ["ruby"], "rb"); - } - - protected getOptions(): Array> { - return [rubyOptions.justTypes, rubyOptions.strictness, rubyOptions.namespace]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - protected get defaultIndentation(): string { - return " "; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): RubyRenderer { - return new RubyRenderer(this, renderContext, getOptionValues(rubyOptions, untypedOptionValues)); - } -} - -const isStartCharacter = isLetterOrUnderscore; - -function isPartCharacter(utf16Unit: number): boolean { - const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); -} - -const legalizeName = legalizeCharacters(isPartCharacter); - -function simpleNameStyle(original: string, uppercase: boolean): string { - if (/^[0-9]+$/.test(original)) { - original = original + "N"; - } - - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - uppercase ? firstUpperWordStyle : allLowerWordStyle, - uppercase ? firstUpperWordStyle : allLowerWordStyle, - allUpperWordStyle, - allUpperWordStyle, - "", - isStartCharacter - ); -} - -function memberNameStyle(original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - allLowerWordStyle, - allLowerWordStyle, - allLowerWordStyle, - allLowerWordStyle, - "_", - isStartCharacter - ); -} - -export class RubyRenderer extends ConvenienceRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - private readonly _options: OptionValues - ) { - super(targetLanguage, renderContext); - } - - protected get commentLineStart(): string { - return "# "; - } - - protected get needsTypeDeclarationBeforeUse(): boolean { - return true; - } - - protected canBeForwardDeclared(t: Type): boolean { - return "class" === t.kind; - } - - protected forbiddenNamesForGlobalNamespace(): string[] { - return keywords.globals.concat(["Types", "JSON", "Dry", "Constructor", "Self"]); - } - - protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { - return { names: forbiddenForObjectProperties, includeGlobalForbidden: true }; - } - - protected makeNamedTypeNamer(): Namer { - return new Namer("types", n => simpleNameStyle(n, true), []); - } - - protected namerForObjectProperty(): Namer { - return new Namer("properties", memberNameStyle, []); - } - - protected makeUnionMemberNamer(): Namer { - return new Namer("properties", memberNameStyle, []); - } - - protected makeEnumCaseNamer(): Namer { - return new Namer("enum-cases", n => simpleNameStyle(n, true), []); - } - - private dryType(t: Type, isOptional = false): Sourcelike { - const optional = isOptional ? ".optional" : ""; - return matchType( - t, - _anyType => ["Types::Any", optional], - _nullType => ["Types::Nil", optional], - _boolType => ["Types::Bool", optional], - _integerType => ["Types::Integer", optional], - _doubleType => ["Types::Double", optional], - _stringType => ["Types::String", optional], - arrayType => ["Types.Array(", this.dryType(arrayType.items), ")", optional], - classType => [this.nameForNamedType(classType), optional], - mapType => ["Types::Hash.meta(of: ", this.dryType(mapType.values), ")", optional], - enumType => ["Types::", this.nameForNamedType(enumType), optional], - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - return [this.dryType(nullable), ".optional"]; - } - - return ["Types.Instance(", this.nameForNamedType(unionType), ")", optional]; - } - ); - } - - private exampleUse(t: Type, exp: Sourcelike, depth = 6, optional = false): Sourcelike { - if (depth-- <= 0) { - return exp; - } - - const safeNav = optional ? "&" : ""; - - return matchType( - t, - _anyType => exp, - _nullType => [exp, ".nil?"], - _boolType => exp, - _integerType => [exp, ".even?"], - _doubleType => exp, - _stringType => exp, - arrayType => this.exampleUse(arrayType.items, [exp, safeNav, ".first"], depth), - classType => { - let info: { name: Name; prop: ClassProperty } | undefined; - this.forEachClassProperty(classType, "none", (name, _json, prop) => { - if (["class", "map", "array"].includes(prop.type.kind)) { - info = { name, prop }; - } else if (info === undefined) { - info = { name, prop }; - } - }); - if (info !== undefined) { - return this.exampleUse(info.prop.type, [exp, safeNav, ".", info.name], depth, info.prop.isOptional); - } - - return exp; - }, - mapType => this.exampleUse(mapType.values, [exp, safeNav, '["…"]'], depth), - enumType => { - let name: Name | undefined; - // FIXME: This is a terrible way to get the first enum case name. - this.forEachEnumCase(enumType, "none", theName => { - if (name === undefined) { - name = theName; - } - }); - if (name !== undefined) { - return [exp, " == ", this.nameForNamedType(enumType), "::", name]; - } - - return exp; - }, - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - if (["class", "map", "array"].includes(nullable.kind)) { - return this.exampleUse(nullable, exp, depth, true); - } - - return [exp, ".nil?"]; - } - - return exp; - } - ); - } - - private jsonSample(t: Type): Sourcelike { - function inner(): string { - if (t instanceof ArrayType) { - return "[…]"; - } else if (t instanceof MapType) { - return "{…}"; - } else if (t instanceof ClassType) { - return "{…}"; - } else { - return "…"; - } - } - - return `"${inner()}"`; - } - - private fromDynamic(t: Type, e: Sourcelike, optional = false, castPrimitives = false): Sourcelike { - const primitiveCast = [this.dryType(t, optional), "[", e, "]"]; - const primitive = castPrimitives ? primitiveCast : e; - const safeAccess = optional ? "&" : ""; - return matchType( - t, - _anyType => primitive, - _nullType => primitive, - _boolType => primitive, - _integerType => primitive, - _doubleType => primitive, - _stringType => primitive, - arrayType => [e, safeAccess, ".map { |x| ", this.fromDynamic(arrayType.items, "x", false, true), " }"], - classType => { - const expression = [this.nameForNamedType(classType), ".from_dynamic!(", e, ")"]; - return optional ? [e, " ? ", expression, " : nil"] : expression; - }, - mapType => [ - ["Types::Hash", optional ? ".optional" : "", "[", e, "]"], - safeAccess, - ".map { |k, v| [k, ", - this.fromDynamic(mapType.values, "v", false, true), - "] }", - safeAccess, - ".to_h" - ], - enumType => { - const expression = ["Types::", this.nameForNamedType(enumType), "[", e, "]"]; - return optional ? [e, ".nil? ? nil : ", expression] : expression; - }, - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - return this.fromDynamic(nullable, e, true); - } - - const expression = [this.nameForNamedType(unionType), ".from_dynamic!(", e, ")"]; - return optional ? [e, " ? ", expression, " : nil"] : expression; - } - ); - } - - private toDynamic(t: Type, e: Sourcelike, optional = false): Sourcelike { - if (this.marshalsImplicitlyToDynamic(t)) { - return e; - } - - return matchType( - t, - _anyType => e, - _nullType => e, - _boolType => e, - _integerType => e, - _doubleType => e, - _stringType => e, - arrayType => [e, optional ? "&" : "", ".map { |x| ", this.toDynamic(arrayType.items, "x"), " }"], - _classType => [e, optional ? "&" : "", ".to_dynamic"], - mapType => [e, optional ? "&" : "", ".map { |k, v| [k, ", this.toDynamic(mapType.values, "v"), "] }.to_h"], - _enumType => e, - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - return this.toDynamic(nullable, e, true); - } - - if (this.marshalsImplicitlyToDynamic(unionType)) { - return e; - } - - return [e, optional ? "&" : "", ".to_dynamic"]; - } - ); - } - - private marshalsImplicitlyToDynamic(t: Type): boolean { - return matchType( - t, - _anyType => true, - _nullType => true, - _boolType => true, - _integerType => true, - _doubleType => true, - _stringType => true, - arrayType => this.marshalsImplicitlyToDynamic(arrayType.items), - _classType => false, - mapType => this.marshalsImplicitlyToDynamic(mapType.values), - _enumType => true, - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - return this.marshalsImplicitlyToDynamic(nullable); - } - - return false; - } - ); - } - - // This is only to be used to allow class properties to possibly - // marshal implicitly. They are allowed to do this because they will - // be checked in Dry::Struct.new - private propertyTypeMarshalsImplicitlyFromDynamic(t: Type): boolean { - return matchType( - t, - _anyType => true, - _nullType => true, - _boolType => true, - _integerType => true, - _doubleType => true, - _stringType => true, - arrayType => this.propertyTypeMarshalsImplicitlyFromDynamic(arrayType.items), - _classType => false, - // Map properties must be checked because Dry:Types doesn't have a generic Map - _mapType => false, - _enumType => true, - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) { - return this.propertyTypeMarshalsImplicitlyFromDynamic(nullable); - } - - return false; - } - ); - } - - private emitBlock(source: Sourcelike, emit: () => void): void { - this.emitLine(source); - this.indent(emit); - this.emitLine("end"); - } - - private emitModule(emit: () => void): void { - const emitModuleInner = (moduleName: string): void => { - const [firstModule, ...subModules] = moduleName.split("::"); - if (subModules.length > 0) { - this.emitBlock(["module ", firstModule], () => { - emitModuleInner(subModules.join("::")); - }); - } else { - this.emitBlock(["module ", moduleName], emit); - } - }; - - if (this._options.namespace !== undefined && this._options.namespace !== "") { - emitModuleInner(this._options.namespace); - } else { - emit(); - } - } - - private emitClass(c: ClassType, className: Name): void { - this.emitDescription(this.descriptionForType(c)); - this.emitBlock(["class ", className, " < Dry::Struct"], () => { - let table: Sourcelike[][] = []; - let count = c.getProperties().size; - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - const last = --count === 0; - const description = this.descriptionForClassProperty(c, jsonName); - const attribute = [ - ["attribute :", name, ","], - [" ", this.dryType(p.type), p.isOptional ? ".optional" : ""] - ]; - if (description !== undefined) { - if (table.length > 0) { - this.emitTable(table); - table = []; - } - - this.ensureBlankLine(); - this.emitDescriptionBlock(description); - this.emitLine(attribute); - if (!last) { - this.ensureBlankLine(); - } - } else { - table.push(attribute); - } - }); - if (table.length > 0) { - this.emitTable(table); - } - - if (this._options.justTypes) { - return; - } - - this.ensureBlankLine(); - this.emitBlock(["def self.from_dynamic!(d)"], () => { - this.emitLine("d = Types::Hash[d]"); - this.emitLine("new("); - this.indent(() => { - const inits: Sourcelike[][] = []; - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - const dynamic = p.isOptional - ? // If key is not found in hash, this will be nil - `d["${stringEscape(jsonName)}"]` - : // This will raise a runtime error if the key is not found in the hash - `d.fetch("${stringEscape(jsonName)}")`; - - if (this.propertyTypeMarshalsImplicitlyFromDynamic(p.type)) { - inits.push([ - [name, ": "], - [dynamic, ","] - ]); - } else { - const expression = this.fromDynamic(p.type, dynamic, p.isOptional); - inits.push([ - [name, ": "], - [expression, ","] - ]); - } - }); - this.emitTable(inits); - }); - this.emitLine(")"); - }); - - this.ensureBlankLine(); - this.emitBlock("def self.from_json!(json)", () => { - this.emitLine("from_dynamic!(JSON.parse(json))"); - }); - - this.ensureBlankLine(); - this.emitBlock(["def to_dynamic"], () => { - this.emitLine("{"); - this.indent(() => { - const inits: Sourcelike[][] = []; - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - const expression = this.toDynamic(p.type, name, p.isOptional); - inits.push([[`"${stringEscape(jsonName)}"`], [" => ", expression, ","]]); - }); - this.emitTable(inits); - }); - this.emitLine("}"); - }); - this.ensureBlankLine(); - this.emitBlock("def to_json(options = nil)", () => { - this.emitLine("JSON.generate(to_dynamic, options)"); - }); - }); - } - - private emitEnum(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - this.emitBlock(["module ", enumName], () => { - const table: Sourcelike[][] = []; - this.forEachEnumCase(e, "none", (name, json) => { - table.push([[name], [` = "${stringEscape(json)}"`]]); - }); - this.emitTable(table); - }); - } - - private emitUnion(u: UnionType, unionName: Name): void { - this.emitDescription(this.descriptionForType(u)); - this.emitBlock(["class ", unionName, " < Dry::Struct"], () => { - const table: Sourcelike[][] = []; - this.forEachUnionMember(u, u.getChildren(), "none", null, (name, t) => { - table.push([["attribute :", name, ", "], [this.dryType(t, true)]]); - }); - this.emitTable(table); - - if (this._options.justTypes) { - return; - } - - this.ensureBlankLine(); - const [maybeNull, nonNulls] = removeNullFromUnion(u, false); - this.emitBlock("def self.from_dynamic!(d)", () => { - const memberNames = Array.from(u.getChildren()).map(member => this.nameForUnionMember(u, member)); - this.forEachUnionMember(u, u.getChildren(), "none", null, (name, t) => { - const nilMembers = memberNames - .filter(n => n !== name) - .map(memberName => [", ", memberName, ": nil"]); - if (this.propertyTypeMarshalsImplicitlyFromDynamic(t)) { - this.emitBlock(["if schema[:", name, "].right.valid? d"], () => { - this.emitLine("return new(", name, ": d", nilMembers, ")"); - }); - } else { - this.emitLine("begin"); - this.indent(() => { - this.emitLine("value = ", this.fromDynamic(t, "d")); - this.emitBlock(["if schema[:", name, "].right.valid? value"], () => { - this.emitLine("return new(", name, ": value", nilMembers, ")"); - }); - }); - this.emitLine("rescue"); - this.emitLine("end"); - } - }); - this.emitLine('raise "Invalid union"'); - }); - - this.ensureBlankLine(); - this.emitBlock("def self.from_json!(json)", () => { - this.emitLine("from_dynamic!(JSON.parse(json))"); - }); - - this.ensureBlankLine(); - this.emitBlock("def to_dynamic", () => { - let first = true; - this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { - this.emitLine(first ? "if" : "elsif", " ", name, " != nil"); - this.indent(() => { - this.emitLine(this.toDynamic(t, name)); - }); - first = false; - }); - if (maybeNull !== null) { - this.emitLine("else"); - this.indent(() => { - this.emitLine("nil"); - }); - } - - this.emitLine("end"); - }); - - this.ensureBlankLine(); - this.emitBlock("def to_json(options = nil)", () => { - this.emitLine("JSON.generate(to_dynamic, options)"); - }); - }); - } - - private emitTypesModule(): void { - this.emitBlock(["module Types"], () => { - this.emitLine("include Dry.Types(default: :nominal)"); - - const declarations: Sourcelike[][] = []; - - if (this._options.strictness !== Strictness.None) { - let has = { int: false, nil: false, bool: false, hash: false, string: false, double: false }; - this.forEachType(t => { - has = { - int: has.int || t.kind === "integer", - nil: has.nil || t.kind === "null", - bool: has.bool || t.kind === "bool", - hash: has.hash || t.kind === "map" || t.kind === "class", - string: has.string || t.kind === "string" || t.kind === "enum", - double: has.double || t.kind === "double" - }; - }); - if (has.int) declarations.push([["Integer"], [` = ${this._options.strictness}Integer`]]); - if (this._options.strictness === Strictness.Strict) { - if (has.nil) declarations.push([["Nil"], [` = ${this._options.strictness}Nil`]]); - } - - if (has.bool) declarations.push([["Bool"], [` = ${this._options.strictness}Bool`]]); - if (has.hash) declarations.push([["Hash"], [` = ${this._options.strictness}Hash`]]); - if (has.string) declarations.push([["String"], [` = ${this._options.strictness}String`]]); - if (has.double) - declarations.push([ - ["Double"], - [` = ${this._options.strictness}Float | ${this._options.strictness}Integer`] - ]); - } - - this.forEachEnum("none", (enumType, enumName) => { - const cases: Sourcelike[][] = []; - this.forEachEnumCase(enumType, "none", (_name, json) => { - cases.push([cases.length === 0 ? "" : ", ", `"${stringEscape(json)}"`]); - }); - declarations.push([[enumName], [" = ", this._options.strictness, "String.enum(", ...cases, ")"]]); - }); - - if (declarations.length > 0) { - this.ensureBlankLine(); - this.emitTable(declarations); - } - }); - } - - protected emitSourceStructure(): void { - if (this.leadingComments !== undefined) { - this.emitComments(this.leadingComments); - } else if (!this._options.justTypes) { - this.emitLine("# This code may look unusually verbose for Ruby (and it is), but"); - this.emitLine("# it performs some subtle and complex validation of JSON data."); - this.emitLine("#"); - this.emitLine("# To parse this JSON, add 'dry-struct' and 'dry-types' gems, then do:"); - this.emitLine("#"); - this.forEachTopLevel("none", (topLevel, name) => { - const variable = modifySource(snakeCase, name); - this.emitLine("# ", variable, " = ", name, ".from_json! ", this.jsonSample(topLevel)); - this.emitLine("# puts ", this.exampleUse(topLevel, variable)); - this.emitLine("#"); - }); - this.emitLine("# If from_json! succeeds, the value returned matches the schema."); - } - - this.ensureBlankLine(); - - this.emitLine("require 'json'"); - this.emitLine("require 'dry-types'"); - this.emitLine("require 'dry-struct'"); - - this.ensureBlankLine(); - - this.emitModule(() => { - this.emitTypesModule(); - - this.forEachDeclaration("leading-and-interposing", decl => { - if (decl.kind === "forward") { - this.emitCommentLines(["(forward declaration)"]); - this.emitModule(() => { - this.emitLine("class ", this.nameForNamedType(decl.type), " < Dry::Struct; end"); - }); - } - }); - - this.forEachNamedType( - "leading-and-interposing", - (c: ClassType, n: Name) => this.emitClass(c, n), - (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n) - ); - - if (!this._options.justTypes) { - this.forEachTopLevel( - "leading-and-interposing", - (topLevel, name) => { - const self = modifySource(snakeCase, name); - - // The json gem defines to_json on maps and primitives, so we only need to supply - // it for arrays. - const needsToJsonDefined = "array" === topLevel.kind; - - const classDeclaration = (): void => { - this.emitBlock(["class ", name], () => { - this.emitBlock(["def self.from_json!(json)"], () => { - if (needsToJsonDefined) { - this.emitLine( - self, - " = ", - this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") - ); - this.emitBlock([self, ".define_singleton_method(:to_json) do"], () => { - this.emitLine("JSON.generate(", this.toDynamic(topLevel, "self"), ")"); - }); - this.emitLine(self); - } else { - this.emitLine( - this.fromDynamic(topLevel, "JSON.parse(json, quirks_mode: true)") - ); - } - }); - }); - }; - - this.emitModule(() => { - classDeclaration(); - }); - }, - t => this.namedTypeToNameForTopLevel(t) === undefined - ); - } - }); - } -} +export { RubyTargetLanguage, rubyOptions } from "./language"; +export { RubyRenderer } from "./RubyRenderer"; diff --git a/packages/quicktype-core/src/language/Ruby/language.ts b/packages/quicktype-core/src/language/Ruby/language.ts new file mode 100644 index 000000000..d0d40af12 --- /dev/null +++ b/packages/quicktype-core/src/language/Ruby/language.ts @@ -0,0 +1,44 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { RubyRenderer } from "./RubyRenderer"; + +export enum Strictness { + Strict = "Strict::", + Coercible = "Coercible::", + None = "Types::" +} + +export const rubyOptions = { + justTypes: new BooleanOption("just-types", "Plain types only", false), + strictness: new EnumOption("strictness", "Type strictness", [ + ["strict", Strictness.Strict], + ["coercible", Strictness.Coercible], + ["none", Strictness.None] + ]), + namespace: new StringOption("namespace", "Specify a wrapping Namespace", "NAME", "", "secondary") +}; + +export class RubyTargetLanguage extends TargetLanguage { + public constructor() { + super("Ruby", ["ruby"], "rb"); + } + + protected getOptions(): Array> { + return [rubyOptions.justTypes, rubyOptions.strictness, rubyOptions.namespace]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + protected get defaultIndentation(): string { + return " "; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): RubyRenderer { + return new RubyRenderer(this, renderContext, getOptionValues(rubyOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/Ruby/utils.ts b/packages/quicktype-core/src/language/Ruby/utils.ts new file mode 100644 index 000000000..669c0127d --- /dev/null +++ b/packages/quicktype-core/src/language/Ruby/utils.ts @@ -0,0 +1,64 @@ +import unicode from "unicode-properties"; + +import * as keywords from "./constants"; + +import { + legalizeCharacters, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allUpperWordStyle, + allLowerWordStyle, + utf32ConcatMap, + isPrintable, + escapeNonPrintableMapper, + intToHex, + isLetterOrUnderscore +} from "../../support/Strings"; + +export const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); +function unicodeEscape(codePoint: number): string { + return "\\u{" + intToHex(codePoint, 0) + "}"; +} + +export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); + +const isStartCharacter = isLetterOrUnderscore; + +function isPartCharacter(utf16Unit: number): boolean { + const category: string = unicode.getCategory(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); +} + +const legalizeName = legalizeCharacters(isPartCharacter); + +export function simpleNameStyle(original: string, uppercase: boolean): string { + if (/^[0-9]+$/.test(original)) { + original = original + "N"; + } + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + uppercase ? firstUpperWordStyle : allLowerWordStyle, + uppercase ? firstUpperWordStyle : allLowerWordStyle, + allUpperWordStyle, + allUpperWordStyle, + "", + isStartCharacter + ); +} + +export function memberNameStyle(original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + allLowerWordStyle, + allLowerWordStyle, + allLowerWordStyle, + allLowerWordStyle, + "_", + isStartCharacter + ); +} From fdef01e225d0d480e4ff9003a23483588ece382d Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 12:05:58 -0700 Subject: [PATCH 47/80] move Python to own dir --- .../JSONPythonRenderer.ts} | 543 +----------------- .../src/language/Python/PythonRenderer.ts | 321 +++++++++++ .../src/language/Python/constants.ts | 59 ++ .../src/language/Python/index.ts | 3 + .../src/language/Python/language.ts | 74 +++ .../src/language/Python/utils.ts | 73 +++ 6 files changed, 541 insertions(+), 532 deletions(-) rename packages/quicktype-core/src/language/{Python.ts => Python/JSONPythonRenderer.ts} (63%) create mode 100644 packages/quicktype-core/src/language/Python/PythonRenderer.ts create mode 100644 packages/quicktype-core/src/language/Python/constants.ts create mode 100644 packages/quicktype-core/src/language/Python/index.ts create mode 100644 packages/quicktype-core/src/language/Python/language.ts create mode 100644 packages/quicktype-core/src/language/Python/utils.ts diff --git a/packages/quicktype-core/src/language/Python.ts b/packages/quicktype-core/src/language/Python/JSONPythonRenderer.ts similarity index 63% rename from packages/quicktype-core/src/language/Python.ts rename to packages/quicktype-core/src/language/Python/JSONPythonRenderer.ts index dc3f5b9e9..28d16eece 100644 --- a/packages/quicktype-core/src/language/Python.ts +++ b/packages/quicktype-core/src/language/Python/JSONPythonRenderer.ts @@ -1,31 +1,9 @@ -import { - arrayIntercalate, - iterableFirst, - iterableSome, - mapSortBy, - mapUpdateInto, - setUnionInto -} from "collection-utils"; -import unicode from "unicode-properties"; - -import { ConvenienceRenderer, type ForbiddenWordsInfo, topLevelNameOrder } from "../ConvenienceRenderer"; -import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type MultiWord, type Sourcelike, modifySource, multiWord, parenIfNeeded, singleWord } from "../Source"; -import { - type WordStyle, - allLowerWordStyle, - allUpperWordStyle, - combineWords, - firstUpperWordStyle, - originalWord, - splitIntoWords, - stringEscape, - utf16LegalizeCharacters -} from "../support/Strings"; -import { assertNever, defined, panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; +import { arrayIntercalate } from "collection-utils"; + +import { topLevelNameOrder } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, funPrefixNamer } from "../../Naming"; +import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../../Source"; +import { assertNever, defined, panic } from "../../support/Support"; import { ChoiceTransformer, DecodingChoiceTransformer, @@ -36,512 +14,13 @@ import { type Transformer, UnionInstantiationTransformer, UnionMemberMatchTransformer, - followTargetType, transformationForType -} from "../Transformers"; -import { - type ClassProperty, - ClassType, - EnumType, - type PrimitiveStringTypeKind, - type TransformedStringTypeKind, - type Type, - UnionType -} from "../Type"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -const forbiddenTypeNames = [ - "Any", - "True", - "False", - "None", - "Enum", - "List", - "Dict", - "Optional", - "Union", - "Iterable", - "Type", - "TypeVar", - "T", - "EnumT" -]; -const forbiddenPropertyNames = [ - "and", - "as", - "assert", - "async", - "await", - "bool", - "break", - "class", - "continue", - "datetime", - "def", - "del", - "dict", - "elif", - "else", - "except", - "finally", - "float", - "for", - "from", - "global", - "if", - "import", - "in", - "int", - "is", - "lambda", - "nonlocal", - "not", - "or", - "pass", - "print", - "raise", - "return", - "self", - "str", - "try", - "while", - "with", - "yield" -]; - -export interface PythonFeatures { - dataClasses: boolean; - typeHints: boolean; -} - -export const pythonOptions = { - features: new EnumOption( - "python-version", - "Python version", - [ - ["3.5", { typeHints: false, dataClasses: false }], - ["3.6", { typeHints: true, dataClasses: false }], - ["3.7", { typeHints: true, dataClasses: true }] - ], - "3.6" - ), - justTypes: new BooleanOption("just-types", "Classes only", false), - nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be Pythonic", true) -}; - -export class PythonTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { - return [pythonOptions.features, pythonOptions.justTypes, pythonOptions.nicePropertyNames]; - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - const dateTimeType = "date-time"; - mapping.set("date", dateTimeType); - mapping.set("time", dateTimeType); - mapping.set("date-time", dateTimeType); - mapping.set("uuid", "uuid"); - mapping.set("integer-string", "integer-string"); - mapping.set("bool-string", "bool-string"); - return mapping; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - public get supportsOptionalClassProperties(): boolean { - return false; - } - - public needsTransformerForType(t: Type): boolean { - if (t instanceof UnionType) { - return iterableSome(t.members, m => this.needsTransformerForType(m)); - } - - return t.kind === "integer-string" || t.kind === "bool-string"; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PythonRenderer { - const options = getOptionValues(pythonOptions, untypedOptionValues); - if (options.justTypes) { - return new PythonRenderer(this, renderContext, options); - } else { - return new JSONPythonRenderer(this, renderContext, options); - } - } -} - -function isNormalizedStartCharacter3(utf16Unit: number): boolean { - // FIXME: add Other_ID_Start - https://docs.python.org/3/reference/lexical_analysis.html#identifiers - const category: string = unicode.getCategory(utf16Unit); - return ["Lu", "Ll", "Lt", "Lm", "Lo", "Nl"].includes(category); -} - -function isNormalizedPartCharacter3(utf16Unit: number): boolean { - // FIXME: add Other_ID_Continue - https://docs.python.org/3/reference/lexical_analysis.html#identifiers - if (isNormalizedStartCharacter3(utf16Unit)) return true; - const category: string = unicode.getCategory(utf16Unit); - return ["Mn", "Mc", "Nd", "Pc"].includes(category); -} - -function isStartCharacter3(utf16Unit: number): boolean { - const s = String.fromCharCode(utf16Unit).normalize("NFKC"); - const l = s.length; - if (l === 0 || !isNormalizedStartCharacter3(s.charCodeAt(0))) return false; - for (let i = 1; i < l; i++) { - if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; - } - - return true; -} - -function isPartCharacter3(utf16Unit: number): boolean { - const s = String.fromCharCode(utf16Unit).normalize("NFKC"); - const l = s.length; - for (let i = 0; i < l; i++) { - if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; - } - - return true; -} - -const legalizeName3 = utf16LegalizeCharacters(isPartCharacter3); - -function classNameStyle(original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName3, - firstUpperWordStyle, - firstUpperWordStyle, - allUpperWordStyle, - allUpperWordStyle, - "", - isStartCharacter3 - ); -} - -function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean): WordStyle { - if (!forceSnakeNameStyle) { - return originalWord; - } - - return uppercase ? allUpperWordStyle : allLowerWordStyle; -} - -function snakeNameStyle(original: string, uppercase: boolean, forceSnakeNameStyle: boolean): string { - const wordStyle = getWordStyle(uppercase, forceSnakeNameStyle); - const separator = forceSnakeNameStyle ? "_" : ""; - const words = splitIntoWords(original); - return combineWords(words, legalizeName3, wordStyle, wordStyle, wordStyle, wordStyle, separator, isStartCharacter3); -} - -export class PythonRenderer extends ConvenienceRenderer { - private readonly imports: Map> = new Map(); - - private readonly declaredTypes: Set = new Set(); - - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - protected readonly pyOptions: OptionValues - ) { - super(targetLanguage, renderContext); - } - - protected forbiddenNamesForGlobalNamespace(): string[] { - return forbiddenTypeNames; - } - - protected forbiddenForObjectProperties(_: ClassType, _classNamed: Name): ForbiddenWordsInfo { - return { names: forbiddenPropertyNames, includeGlobalForbidden: false }; - } - - protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("type", classNameStyle); - } - - protected namerForObjectProperty(): Namer { - return funPrefixNamer("property", s => snakeNameStyle(s, false, this.pyOptions.nicePropertyNames)); - } - - protected makeUnionMemberNamer(): null { - return null; - } - - protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enum-case", s => snakeNameStyle(s, true, this.pyOptions.nicePropertyNames)); - } - - protected get commentLineStart(): string { - return "# "; - } - - protected emitDescriptionBlock(lines: Sourcelike[]): void { - if (lines.length === 1) { - const docstring = modifySource(content => { - if (content.endsWith('"')) { - return content.slice(0, -1) + '\\"'; - } - - return content; - }, lines[0]); - this.emitComments([{ customLines: [docstring], lineStart: '"""', lineEnd: '"""' }]); - } else { - this.emitCommentLines(lines, { - firstLineStart: '"""', - lineStart: "", - afterComment: '"""' - }); - } - } - - protected get needsTypeDeclarationBeforeUse(): boolean { - return true; - } - - protected canBeForwardDeclared(t: Type): boolean { - const kind = t.kind; - return kind === "class" || kind === "enum"; - } - - protected emitBlock(line: Sourcelike, f: () => void): void { - this.emitLine(line); - this.indent(f); - } - - protected string(s: string): Sourcelike { - const openQuote = '"'; - return [openQuote, stringEscape(s), '"']; - } - - protected withImport(module: string, name: string): Sourcelike { - if (this.pyOptions.features.typeHints || module !== "typing") { - // FIXME: This is ugly. We should rather not generate that import in the first - // place, but right now we just make the type source and then throw it away. It's - // not a performance issue, so it's fine, I just bemoan this special case, and - // potential others down the road. - mapUpdateInto(this.imports, module, s => (s ? setUnionInto(s, [name]) : new Set([name]))); - } - - return name; - } - - protected withTyping(name: string): Sourcelike { - return this.withImport("typing", name); - } - - protected namedType(t: Type): Sourcelike { - const name = this.nameForNamedType(t); - if (this.declaredTypes.has(t)) return name; - return ["'", name, "'"]; - } - - protected pythonType(t: Type, _isRootTypeDef = false): Sourcelike { - const actualType = followTargetType(t); - - return matchType( - actualType, - _anyType => this.withTyping("Any"), - _nullType => "None", - _boolType => "bool", - _integerType => "int", - _doubletype => "float", - _stringType => "str", - arrayType => [this.withTyping("List"), "[", this.pythonType(arrayType.items), "]"], - classType => this.namedType(classType), - mapType => [this.withTyping("Dict"), "[str, ", this.pythonType(mapType.values), "]"], - enumType => this.namedType(enumType), - unionType => { - const [hasNull, nonNulls] = removeNullFromUnion(unionType); - const memberTypes = Array.from(nonNulls).map(m => this.pythonType(m)); - - if (hasNull !== null) { - let rest: string[] = []; - if (!this.getAlphabetizeProperties() && this.pyOptions.features.dataClasses && _isRootTypeDef) { - // Only push "= None" if this is a root level type def - // otherwise we may get type defs like List[Optional[int] = None] - // which are invalid - rest.push(" = None"); - } - - if (nonNulls.size > 1) { - this.withImport("typing", "Union"); - return [ - this.withTyping("Optional"), - "[Union[", - arrayIntercalate(", ", memberTypes), - "]]", - ...rest - ]; - } else { - return [this.withTyping("Optional"), "[", defined(iterableFirst(memberTypes)), "]", ...rest]; - } - } else { - return [this.withTyping("Union"), "[", arrayIntercalate(", ", memberTypes), "]"]; - } - }, - transformedStringType => { - if (transformedStringType.kind === "date-time") { - return this.withImport("datetime", "datetime"); - } - - if (transformedStringType.kind === "uuid") { - return this.withImport("uuid", "UUID"); - } - - return panic(`Transformed type ${transformedStringType.kind} not supported`); - } - ); - } - - protected declarationLine(t: Type): Sourcelike { - if (t instanceof ClassType) { - return ["class ", this.nameForNamedType(t), ":"]; - } - - if (t instanceof EnumType) { - return ["class ", this.nameForNamedType(t), "(", this.withImport("enum", "Enum"), "):"]; - } - - return panic(`Can't declare type ${t.kind}`); - } +} from "../../Transformers"; +import { type ClassType, type Type } from "../../Type"; +import { matchType } from "../../TypeUtils"; - protected declareType(t: T, emitter: () => void): void { - this.emitBlock(this.declarationLine(t), () => { - this.emitDescription(this.descriptionForType(t)); - emitter(); - }); - this.declaredTypes.add(t); - } - - protected emitClassMembers(t: ClassType): void { - if (this.pyOptions.features.dataClasses) return; - - const args: Sourcelike[] = []; - this.forEachClassProperty(t, "none", (name, _, cp) => { - args.push([name, this.typeHint(": ", this.pythonType(cp.type))]); - }); - this.emitBlock( - ["def __init__(self, ", arrayIntercalate(", ", args), ")", this.typeHint(" -> None"), ":"], - () => { - if (args.length === 0) { - this.emitLine("pass"); - } else { - this.forEachClassProperty(t, "none", name => { - this.emitLine("self.", name, " = ", name); - }); - } - } - ); - } - - protected typeHint(...sl: Sourcelike[]): Sourcelike { - if (this.pyOptions.features.typeHints) { - return sl; - } - - return []; - } - - protected typingDecl(name: Sourcelike, type: string): Sourcelike { - return [name, this.typeHint(": ", this.withTyping(type))]; - } - - protected typingReturn(type: string): Sourcelike { - return this.typeHint(" -> ", this.withTyping(type)); - } - - protected sortClassProperties( - properties: ReadonlyMap, - propertyNames: ReadonlyMap - ): ReadonlyMap { - if (this.pyOptions.features.dataClasses) { - return mapSortBy(properties, (p: ClassProperty) => { - return (p.type instanceof UnionType && nullableFromUnion(p.type) != null) || p.isOptional ? 1 : 0; - }); - } else { - return super.sortClassProperties(properties, propertyNames); - } - } - - protected emitClass(t: ClassType): void { - if (this.pyOptions.features.dataClasses) { - this.emitLine("@", this.withImport("dataclasses", "dataclass")); - } - - this.declareType(t, () => { - if (this.pyOptions.features.typeHints) { - if (t.getProperties().size === 0) { - this.emitLine("pass"); - } else { - this.forEachClassProperty(t, "none", (name, jsonName, cp) => { - this.emitLine(name, this.typeHint(": ", this.pythonType(cp.type, true))); - this.emitDescription(this.descriptionForClassProperty(t, jsonName)); - }); - } - - this.ensureBlankLine(); - } - - this.emitClassMembers(t); - }); - } - - protected emitEnum(t: EnumType): void { - this.declareType(t, () => { - this.forEachEnumCase(t, "none", (name, jsonName) => { - this.emitLine([name, " = ", this.string(jsonName)]); - }); - }); - } - - protected emitImports(): void { - this.imports.forEach((names, module) => { - this.emitLine("from ", module, " import ", Array.from(names).join(", ")); - }); - } - - protected emitSupportCode(): void { - return; - } - - protected emitClosingCode(): void { - return; - } - - protected emitSourceStructure(_givenOutputFilename: string): void { - const declarationLines = this.gatherSource(() => { - this.forEachNamedType( - ["interposing", 2], - (c: ClassType) => this.emitClass(c), - e => this.emitEnum(e), - _u => { - return; - } - ); - }); - - const closingLines = this.gatherSource(() => this.emitClosingCode()); - const supportLines = this.gatherSource(() => this.emitSupportCode()); - - if (this.leadingComments !== undefined) { - this.emitComments(this.leadingComments); - } - - this.ensureBlankLine(); - this.emitImports(); - this.ensureBlankLine(2); - this.emitGatheredSource(supportLines); - this.ensureBlankLine(2); - this.emitGatheredSource(declarationLines); - this.ensureBlankLine(2); - this.emitGatheredSource(closingLines); - } -} +import { PythonRenderer } from "./PythonRenderer"; +import { snakeNameStyle } from "./utils"; export type ConverterFunction = | "none" diff --git a/packages/quicktype-core/src/language/Python/PythonRenderer.ts b/packages/quicktype-core/src/language/Python/PythonRenderer.ts new file mode 100644 index 000000000..63ec3c70d --- /dev/null +++ b/packages/quicktype-core/src/language/Python/PythonRenderer.ts @@ -0,0 +1,321 @@ +import { arrayIntercalate, iterableFirst, mapSortBy, mapUpdateInto, setUnionInto } from "collection-utils"; + +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { stringEscape } from "../../support/Strings"; +import { defined, panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { followTargetType } from "../../Transformers"; +import { type ClassProperty, ClassType, EnumType, type Type, UnionType } from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { forbiddenPropertyNames, forbiddenTypeNames } from "./constants"; +import { type pythonOptions } from "./language"; +import { classNameStyle, snakeNameStyle } from "./utils"; + +export class PythonRenderer extends ConvenienceRenderer { + private readonly imports: Map> = new Map(); + + private readonly declaredTypes: Set = new Set(); + + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + protected readonly pyOptions: OptionValues + ) { + super(targetLanguage, renderContext); + } + + protected forbiddenNamesForGlobalNamespace(): readonly string[] { + return forbiddenTypeNames; + } + + protected forbiddenForObjectProperties(_: ClassType, _classNamed: Name): ForbiddenWordsInfo { + return { names: forbiddenPropertyNames as unknown as string[], includeGlobalForbidden: false }; + } + + protected makeNamedTypeNamer(): Namer { + return funPrefixNamer("type", classNameStyle); + } + + protected namerForObjectProperty(): Namer { + return funPrefixNamer("property", s => snakeNameStyle(s, false, this.pyOptions.nicePropertyNames)); + } + + protected makeUnionMemberNamer(): null { + return null; + } + + protected makeEnumCaseNamer(): Namer { + return funPrefixNamer("enum-case", s => snakeNameStyle(s, true, this.pyOptions.nicePropertyNames)); + } + + protected get commentLineStart(): string { + return "# "; + } + + protected emitDescriptionBlock(lines: Sourcelike[]): void { + if (lines.length === 1) { + const docstring = modifySource(content => { + if (content.endsWith('"')) { + return content.slice(0, -1) + '\\"'; + } + + return content; + }, lines[0]); + this.emitComments([{ customLines: [docstring], lineStart: '"""', lineEnd: '"""' }]); + } else { + this.emitCommentLines(lines, { + firstLineStart: '"""', + lineStart: "", + afterComment: '"""' + }); + } + } + + protected get needsTypeDeclarationBeforeUse(): boolean { + return true; + } + + protected canBeForwardDeclared(t: Type): boolean { + const kind = t.kind; + return kind === "class" || kind === "enum"; + } + + protected emitBlock(line: Sourcelike, f: () => void): void { + this.emitLine(line); + this.indent(f); + } + + protected string(s: string): Sourcelike { + const openQuote = '"'; + return [openQuote, stringEscape(s), '"']; + } + + protected withImport(module: string, name: string): Sourcelike { + if (this.pyOptions.features.typeHints || module !== "typing") { + // FIXME: This is ugly. We should rather not generate that import in the first + // place, but right now we just make the type source and then throw it away. It's + // not a performance issue, so it's fine, I just bemoan this special case, and + // potential others down the road. + mapUpdateInto(this.imports, module, s => (s ? setUnionInto(s, [name]) : new Set([name]))); + } + + return name; + } + + protected withTyping(name: string): Sourcelike { + return this.withImport("typing", name); + } + + protected namedType(t: Type): Sourcelike { + const name = this.nameForNamedType(t); + if (this.declaredTypes.has(t)) return name; + return ["'", name, "'"]; + } + + protected pythonType(t: Type, _isRootTypeDef = false): Sourcelike { + const actualType = followTargetType(t); + + return matchType( + actualType, + _anyType => this.withTyping("Any"), + _nullType => "None", + _boolType => "bool", + _integerType => "int", + _doubletype => "float", + _stringType => "str", + arrayType => [this.withTyping("List"), "[", this.pythonType(arrayType.items), "]"], + classType => this.namedType(classType), + mapType => [this.withTyping("Dict"), "[str, ", this.pythonType(mapType.values), "]"], + enumType => this.namedType(enumType), + unionType => { + const [hasNull, nonNulls] = removeNullFromUnion(unionType); + const memberTypes = Array.from(nonNulls).map(m => this.pythonType(m)); + + if (hasNull !== null) { + let rest: string[] = []; + if (!this.getAlphabetizeProperties() && this.pyOptions.features.dataClasses && _isRootTypeDef) { + // Only push "= None" if this is a root level type def + // otherwise we may get type defs like List[Optional[int] = None] + // which are invalid + rest.push(" = None"); + } + + if (nonNulls.size > 1) { + this.withImport("typing", "Union"); + return [ + this.withTyping("Optional"), + "[Union[", + arrayIntercalate(", ", memberTypes), + "]]", + ...rest + ]; + } else { + return [this.withTyping("Optional"), "[", defined(iterableFirst(memberTypes)), "]", ...rest]; + } + } else { + return [this.withTyping("Union"), "[", arrayIntercalate(", ", memberTypes), "]"]; + } + }, + transformedStringType => { + if (transformedStringType.kind === "date-time") { + return this.withImport("datetime", "datetime"); + } + + if (transformedStringType.kind === "uuid") { + return this.withImport("uuid", "UUID"); + } + + return panic(`Transformed type ${transformedStringType.kind} not supported`); + } + ); + } + + protected declarationLine(t: Type): Sourcelike { + if (t instanceof ClassType) { + return ["class ", this.nameForNamedType(t), ":"]; + } + + if (t instanceof EnumType) { + return ["class ", this.nameForNamedType(t), "(", this.withImport("enum", "Enum"), "):"]; + } + + return panic(`Can't declare type ${t.kind}`); + } + + protected declareType(t: T, emitter: () => void): void { + this.emitBlock(this.declarationLine(t), () => { + this.emitDescription(this.descriptionForType(t)); + emitter(); + }); + this.declaredTypes.add(t); + } + + protected emitClassMembers(t: ClassType): void { + if (this.pyOptions.features.dataClasses) return; + + const args: Sourcelike[] = []; + this.forEachClassProperty(t, "none", (name, _, cp) => { + args.push([name, this.typeHint(": ", this.pythonType(cp.type))]); + }); + this.emitBlock( + ["def __init__(self, ", arrayIntercalate(", ", args), ")", this.typeHint(" -> None"), ":"], + () => { + if (args.length === 0) { + this.emitLine("pass"); + } else { + this.forEachClassProperty(t, "none", name => { + this.emitLine("self.", name, " = ", name); + }); + } + } + ); + } + + protected typeHint(...sl: Sourcelike[]): Sourcelike { + if (this.pyOptions.features.typeHints) { + return sl; + } + + return []; + } + + protected typingDecl(name: Sourcelike, type: string): Sourcelike { + return [name, this.typeHint(": ", this.withTyping(type))]; + } + + protected typingReturn(type: string): Sourcelike { + return this.typeHint(" -> ", this.withTyping(type)); + } + + protected sortClassProperties( + properties: ReadonlyMap, + propertyNames: ReadonlyMap + ): ReadonlyMap { + if (this.pyOptions.features.dataClasses) { + return mapSortBy(properties, (p: ClassProperty) => { + return (p.type instanceof UnionType && nullableFromUnion(p.type) != null) || p.isOptional ? 1 : 0; + }); + } else { + return super.sortClassProperties(properties, propertyNames); + } + } + + protected emitClass(t: ClassType): void { + if (this.pyOptions.features.dataClasses) { + this.emitLine("@", this.withImport("dataclasses", "dataclass")); + } + + this.declareType(t, () => { + if (this.pyOptions.features.typeHints) { + if (t.getProperties().size === 0) { + this.emitLine("pass"); + } else { + this.forEachClassProperty(t, "none", (name, jsonName, cp) => { + this.emitLine(name, this.typeHint(": ", this.pythonType(cp.type, true))); + this.emitDescription(this.descriptionForClassProperty(t, jsonName)); + }); + } + + this.ensureBlankLine(); + } + + this.emitClassMembers(t); + }); + } + + protected emitEnum(t: EnumType): void { + this.declareType(t, () => { + this.forEachEnumCase(t, "none", (name, jsonName) => { + this.emitLine([name, " = ", this.string(jsonName)]); + }); + }); + } + + protected emitImports(): void { + this.imports.forEach((names, module) => { + this.emitLine("from ", module, " import ", Array.from(names).join(", ")); + }); + } + + protected emitSupportCode(): void { + return; + } + + protected emitClosingCode(): void { + return; + } + + protected emitSourceStructure(_givenOutputFilename: string): void { + const declarationLines = this.gatherSource(() => { + this.forEachNamedType( + ["interposing", 2], + (c: ClassType) => this.emitClass(c), + e => this.emitEnum(e), + _u => { + return; + } + ); + }); + + const closingLines = this.gatherSource(() => this.emitClosingCode()); + const supportLines = this.gatherSource(() => this.emitSupportCode()); + + if (this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + } + + this.ensureBlankLine(); + this.emitImports(); + this.ensureBlankLine(2); + this.emitGatheredSource(supportLines); + this.ensureBlankLine(2); + this.emitGatheredSource(declarationLines); + this.ensureBlankLine(2); + this.emitGatheredSource(closingLines); + } +} diff --git a/packages/quicktype-core/src/language/Python/constants.ts b/packages/quicktype-core/src/language/Python/constants.ts new file mode 100644 index 000000000..0e725bf50 --- /dev/null +++ b/packages/quicktype-core/src/language/Python/constants.ts @@ -0,0 +1,59 @@ +export const forbiddenTypeNames = [ + "Any", + "True", + "False", + "None", + "Enum", + "List", + "Dict", + "Optional", + "Union", + "Iterable", + "Type", + "TypeVar", + "T", + "EnumT" +] as const; + +export const forbiddenPropertyNames = [ + "and", + "as", + "assert", + "async", + "await", + "bool", + "break", + "class", + "continue", + "datetime", + "def", + "del", + "dict", + "elif", + "else", + "except", + "finally", + "float", + "for", + "from", + "global", + "if", + "import", + "in", + "int", + "is", + "lambda", + "nonlocal", + "not", + "or", + "pass", + "print", + "raise", + "return", + "self", + "str", + "try", + "while", + "with", + "yield" +] as const; diff --git a/packages/quicktype-core/src/language/Python/index.ts b/packages/quicktype-core/src/language/Python/index.ts new file mode 100644 index 000000000..7c7b92ba3 --- /dev/null +++ b/packages/quicktype-core/src/language/Python/index.ts @@ -0,0 +1,3 @@ +export { PythonTargetLanguage, pythonOptions } from "./language"; +export { PythonRenderer } from "./PythonRenderer"; +export { JSONPythonRenderer } from "./JSONPythonRenderer"; diff --git a/packages/quicktype-core/src/language/Python/language.ts b/packages/quicktype-core/src/language/Python/language.ts new file mode 100644 index 000000000..e6aac1d87 --- /dev/null +++ b/packages/quicktype-core/src/language/Python/language.ts @@ -0,0 +1,74 @@ +import { iterableSome } from "collection-utils"; + +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind, type Type, UnionType } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { JSONPythonRenderer } from "./JSONPythonRenderer"; +import { PythonRenderer } from "./PythonRenderer"; + +export interface PythonFeatures { + dataClasses: boolean; + typeHints: boolean; +} + +export const pythonOptions = { + features: new EnumOption( + "python-version", + "Python version", + [ + ["3.5", { typeHints: false, dataClasses: false }], + ["3.6", { typeHints: true, dataClasses: false }], + ["3.7", { typeHints: true, dataClasses: true }] + ], + "3.6" + ), + justTypes: new BooleanOption("just-types", "Classes only", false), + nicePropertyNames: new BooleanOption("nice-property-names", "Transform property names to be Pythonic", true) +}; + +export class PythonTargetLanguage extends TargetLanguage { + protected getOptions(): Array> { + return [pythonOptions.features, pythonOptions.justTypes, pythonOptions.nicePropertyNames]; + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + const dateTimeType = "date-time"; + mapping.set("date", dateTimeType); + mapping.set("time", dateTimeType); + mapping.set("date-time", dateTimeType); + mapping.set("uuid", "uuid"); + mapping.set("integer-string", "integer-string"); + mapping.set("bool-string", "bool-string"); + return mapping; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + public get supportsOptionalClassProperties(): boolean { + return false; + } + + public needsTransformerForType(t: Type): boolean { + if (t instanceof UnionType) { + return iterableSome(t.members, m => this.needsTransformerForType(m)); + } + + return t.kind === "integer-string" || t.kind === "bool-string"; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PythonRenderer { + const options = getOptionValues(pythonOptions, untypedOptionValues); + if (options.justTypes) { + return new PythonRenderer(this, renderContext, options); + } else { + return new JSONPythonRenderer(this, renderContext, options); + } + } +} diff --git a/packages/quicktype-core/src/language/Python/utils.ts b/packages/quicktype-core/src/language/Python/utils.ts new file mode 100644 index 000000000..8145ff018 --- /dev/null +++ b/packages/quicktype-core/src/language/Python/utils.ts @@ -0,0 +1,73 @@ +import { + splitIntoWords, + combineWords, + firstUpperWordStyle, + utf16LegalizeCharacters, + allUpperWordStyle, + allLowerWordStyle, + originalWord +} from "../../support/Strings"; + +import unicode from "unicode-properties"; + +function isNormalizedStartCharacter3(utf16Unit: number): boolean { + // FIXME: add Other_ID_Start - https://docs.python.org/3/reference/lexical_analysis.html#identifiers + const category: string = unicode.getCategory(utf16Unit); + return ["Lu", "Ll", "Lt", "Lm", "Lo", "Nl"].indexOf(category) >= 0; +} + +function isNormalizedPartCharacter3(utf16Unit: number): boolean { + // FIXME: add Other_ID_Continue - https://docs.python.org/3/reference/lexical_analysis.html#identifiers + if (isNormalizedStartCharacter3(utf16Unit)) return true; + const category: string = unicode.getCategory(utf16Unit); + return ["Mn", "Mc", "Nd", "Pc"].indexOf(category) >= 0; +} + +function isStartCharacter3(utf16Unit: number): boolean { + const s = String.fromCharCode(utf16Unit).normalize("NFKC"); + const l = s.length; + if (l === 0 || !isNormalizedStartCharacter3(s.charCodeAt(0))) return false; + for (let i = 1; i < l; i++) { + if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; + } + return true; +} + +function isPartCharacter3(utf16Unit: number): boolean { + const s = String.fromCharCode(utf16Unit).normalize("NFKC"); + const l = s.length; + for (let i = 0; i < l; i++) { + if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; + } + return true; +} + +const legalizeName3 = utf16LegalizeCharacters(isPartCharacter3); + +export function classNameStyle(original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName3, + firstUpperWordStyle, + firstUpperWordStyle, + allUpperWordStyle, + allUpperWordStyle, + "", + isStartCharacter3 + ); +} + +function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean) { + if (!forceSnakeNameStyle) { + return originalWord; + } + return uppercase ? allUpperWordStyle : allLowerWordStyle; +} + +export function snakeNameStyle(original: string, uppercase: boolean, forceSnakeNameStyle: boolean): string { + const wordStyle = getWordStyle(uppercase, forceSnakeNameStyle); + const separator = forceSnakeNameStyle ? "_" : ""; + const words = splitIntoWords(original); + return combineWords(words, legalizeName3, wordStyle, wordStyle, wordStyle, wordStyle, separator, isStartCharacter3); +} From df9a4cc77453be05801497d7f2bec26c6adb0f20 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 12:08:20 -0700 Subject: [PATCH 48/80] move Pike to own dir --- .../{Pike.ts => Pike/PikeRenderer.ts} | 103 +++--------------- .../src/language/Pike/constants.ts | 54 +++++++++ .../quicktype-core/src/language/Pike/index.ts | 2 + .../src/language/Pike/language.ts | 22 ++++ .../quicktype-core/src/language/Pike/utils.ts | 7 ++ 5 files changed, 102 insertions(+), 86 deletions(-) rename packages/quicktype-core/src/language/{Pike.ts => Pike/PikeRenderer.ts} (81%) create mode 100644 packages/quicktype-core/src/language/Pike/constants.ts create mode 100644 packages/quicktype-core/src/language/Pike/index.ts create mode 100644 packages/quicktype-core/src/language/Pike/language.ts create mode 100644 packages/quicktype-core/src/language/Pike/utils.ts diff --git a/packages/quicktype-core/src/language/Pike.ts b/packages/quicktype-core/src/language/Pike/PikeRenderer.ts similarity index 81% rename from packages/quicktype-core/src/language/Pike.ts rename to packages/quicktype-core/src/language/Pike/PikeRenderer.ts index ea7f9d3a5..01e383c6e 100644 --- a/packages/quicktype-core/src/language/Pike.ts +++ b/packages/quicktype-core/src/language/Pike/PikeRenderer.ts @@ -1,89 +1,20 @@ -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { type Option } from "../RendererOptions"; -import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../Source"; -import { isLetterOrUnderscoreOrDigit, legalizeCharacters, makeNameStyle, stringEscape } from "../support/Strings"; -import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, type ClassType, type EnumType, MapType, PrimitiveType, type Type, type UnionType } from "../Type"; -import { type FixMeOptionsAnyType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export const pikeOptions = {}; - -const keywords = [ - "auto", - "nomask", - "final", - "static", - "extern", - "private", - "local", - "public", - "protected", - "inline", - "optional", - "variant", - "void", - "mixed", - "array", - "__attribute__", - "__deprecated__", - "mapping", - "multiset", - "object", - "function", - "__func__", - "program", - "string", - "float", - "int", - "enum", - "typedef", - "if", - "do", - "for", - "while", - "else", - "foreach", - "catch", - "gauge", - "class", - "break", - "case", - "const", - "constant", - "continue", - "default", - "import", - "inherit", - "lambda", - "predef", - "return", - "sscanf", - "switch", - "typeof", - "global" -]; - -const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); -const enumNamingFunction = funPrefixNamer("enumNamer", makeNameStyle("upper-underscore", legalizeName)); -const namingFunction = funPrefixNamer("genericNamer", makeNameStyle("underscore", legalizeName)); -const namedTypeNamingFunction = funPrefixNamer("typeNamer", makeNameStyle("pascal", legalizeName)); - -export class PikeTargetLanguage extends TargetLanguage { - public constructor() { - super("Pike", ["pike", "pikelang"], "pmod"); - } - - protected getOptions(): Array> { - return []; - } - - protected makeRenderer(renderContext: RenderContext): PikeRenderer { - return new PikeRenderer(this, renderContext); - } -} +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer } from "../../Naming"; +import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../../Source"; +import { stringEscape } from "../../support/Strings"; +import { + ArrayType, + type ClassType, + type EnumType, + MapType, + PrimitiveType, + type Type, + type UnionType +} from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { enumNamingFunction, namedTypeNamingFunction, namingFunction } from "./utils"; export class PikeRenderer extends ConvenienceRenderer { protected emitSourceStructure(): void { diff --git a/packages/quicktype-core/src/language/Pike/constants.ts b/packages/quicktype-core/src/language/Pike/constants.ts new file mode 100644 index 000000000..d3927948f --- /dev/null +++ b/packages/quicktype-core/src/language/Pike/constants.ts @@ -0,0 +1,54 @@ +export const keywords = [ + "auto", + "nomask", + "final", + "static", + "extern", + "private", + "local", + "public", + "protected", + "inline", + "optional", + "variant", + "void", + "mixed", + "array", + "__attribute__", + "__deprecated__", + "mapping", + "multiset", + "object", + "function", + "__func__", + "program", + "string", + "float", + "int", + "enum", + "typedef", + "if", + "do", + "for", + "while", + "else", + "foreach", + "catch", + "gauge", + "class", + "break", + "case", + "const", + "constant", + "continue", + "default", + "import", + "inherit", + "lambda", + "predef", + "return", + "sscanf", + "switch", + "typeof", + "global" +] as const; diff --git a/packages/quicktype-core/src/language/Pike/index.ts b/packages/quicktype-core/src/language/Pike/index.ts new file mode 100644 index 000000000..2b80f3674 --- /dev/null +++ b/packages/quicktype-core/src/language/Pike/index.ts @@ -0,0 +1,2 @@ +export { PikeTargetLanguage, pikeOptions } from "./language"; +export { PikeRenderer } from "./PikeRenderer"; diff --git a/packages/quicktype-core/src/language/Pike/language.ts b/packages/quicktype-core/src/language/Pike/language.ts new file mode 100644 index 000000000..1772085a0 --- /dev/null +++ b/packages/quicktype-core/src/language/Pike/language.ts @@ -0,0 +1,22 @@ +import { type RenderContext } from "../../Renderer"; +import { type Option } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType } from "../../types"; + +import { PikeRenderer } from "./PikeRenderer"; + +export const pikeOptions = {}; + +export class PikeTargetLanguage extends TargetLanguage { + public constructor() { + super("Pike", ["pike", "pikelang"], "pmod"); + } + + protected getOptions(): Array> { + return []; + } + + protected makeRenderer(renderContext: RenderContext): PikeRenderer { + return new PikeRenderer(this, renderContext); + } +} diff --git a/packages/quicktype-core/src/language/Pike/utils.ts b/packages/quicktype-core/src/language/Pike/utils.ts new file mode 100644 index 000000000..c672bb1d2 --- /dev/null +++ b/packages/quicktype-core/src/language/Pike/utils.ts @@ -0,0 +1,7 @@ +import { funPrefixNamer } from "../../Naming"; +import { legalizeCharacters, isLetterOrUnderscoreOrDigit, makeNameStyle } from "../../support/Strings"; + +const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); +export const enumNamingFunction = funPrefixNamer("enumNamer", makeNameStyle("upper-underscore", legalizeName)); +export const namingFunction = funPrefixNamer("genericNamer", makeNameStyle("underscore", legalizeName)); +export const namedTypeNamingFunction = funPrefixNamer("typeNamer", makeNameStyle("pascal", legalizeName)); From a62c9dea61c6217cd3ed264a39a96a76def21914 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 12:12:05 -0700 Subject: [PATCH 49/80] move Php to own dir --- .../language/{Php.ts => Php/PhpRenderer.ts} | 110 +++--------------- .../quicktype-core/src/language/Php/index.ts | 2 + .../src/language/Php/language.ts | 46 ++++++++ .../quicktype-core/src/language/Php/utils.ts | 47 ++++++++ 4 files changed, 110 insertions(+), 95 deletions(-) rename packages/quicktype-core/src/language/{Php.ts => Php/PhpRenderer.ts} (91%) create mode 100644 packages/quicktype-core/src/language/Php/index.ts create mode 100644 packages/quicktype-core/src/language/Php/language.ts create mode 100644 packages/quicktype-core/src/language/Php/utils.ts diff --git a/packages/quicktype-core/src/language/Php.ts b/packages/quicktype-core/src/language/Php/PhpRenderer.ts similarity index 91% rename from packages/quicktype-core/src/language/Php.ts rename to packages/quicktype-core/src/language/Php/PhpRenderer.ts index e448bb1ee..0c6e3683b 100644 --- a/packages/quicktype-core/src/language/Php.ts +++ b/packages/quicktype-core/src/language/Php/PhpRenderer.ts @@ -1,100 +1,20 @@ import * as _ from "lodash"; -import { type PrimitiveStringTypeKind, type StringTypeMapping, type TransformedStringTypeKind } from ".."; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated } from "../Source"; -import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; -import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - escapeNonPrintableMapper, - firstUpperWordStyle, - isAscii, - isDigit, - isLetter, - splitIntoWords, - standardUnicodeHexEscape, - utf16ConcatMap, - utf16LegalizeCharacters -} from "../support/Strings"; -import { defined } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; - -export const phpOptions = { - withGet: new BooleanOption("with-get", "Create Getter", true), - fastGet: new BooleanOption("fast-get", "getter without validation", false), - withSet: new BooleanOption("with-set", "Create Setter", false), - withClosing: new BooleanOption("with-closing", "PHP Closing Tag", false), - acronymStyle: acronymOption(AcronymStyleOptions.Pascal) -}; - -export class PhpTargetLanguage extends TargetLanguage { - public constructor() { - super("PHP", ["php"], "php"); - } - - protected getOptions(): Array> { - return _.values(phpOptions); - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PhpRenderer { - const options = getOptionValues(phpOptions, untypedOptionValues); - return new PhpRenderer(this, renderContext, options); - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - mapping.set("date", "date"); // TODO is not implemented yet - mapping.set("time", "time"); // TODO is not implemented yet - mapping.set("uuid", "uuid"); // TODO is not implemented yet - mapping.set("date-time", "date-time"); - return mapping; - } -} - -export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); - -function isStartCharacter(codePoint: number): boolean { - if (codePoint === 0x5f) return true; // underscore - return isAscii(codePoint) && isLetter(codePoint); -} - -function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); -} - -const legalizeName = utf16LegalizeCharacters(isPartCharacter); - -export function phpNameStyle( - startWithUpper: boolean, - upperUnderscore: boolean, - original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle -): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - upperUnderscore ? allUpperWordStyle : startWithUpper ? firstUpperWordStyle : allLowerWordStyle, - upperUnderscore ? allUpperWordStyle : firstUpperWordStyle, - upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, - acronymsStyle, - upperUnderscore ? "_" : "", - isStartCharacter - ); -} +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { acronymStyle } from "../../support/Acronyms"; +import { stringEscape } from "../../support/Strings"; +import { defined } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../../Type"; +import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../../TypeUtils"; + +import { type phpOptions } from "./language"; +import { phpNameStyle } from "./utils"; export interface FunctionNames { readonly from: Name; diff --git a/packages/quicktype-core/src/language/Php/index.ts b/packages/quicktype-core/src/language/Php/index.ts new file mode 100644 index 000000000..2e11f2650 --- /dev/null +++ b/packages/quicktype-core/src/language/Php/index.ts @@ -0,0 +1,2 @@ +export { PhpTargetLanguage, phpOptions } from "./language"; +export { PhpRenderer } from "./PhpRenderer"; diff --git a/packages/quicktype-core/src/language/Php/language.ts b/packages/quicktype-core/src/language/Php/language.ts new file mode 100644 index 000000000..cfcfe9654 --- /dev/null +++ b/packages/quicktype-core/src/language/Php/language.ts @@ -0,0 +1,46 @@ +import * as _ from "lodash"; + +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, type Option, getOptionValues } from "../../RendererOptions"; +import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { PhpRenderer } from "./PhpRenderer"; + +export const phpOptions = { + withGet: new BooleanOption("with-get", "Create Getter", true), + fastGet: new BooleanOption("fast-get", "getter without validation", false), + withSet: new BooleanOption("with-set", "Create Setter", false), + withClosing: new BooleanOption("with-closing", "PHP Closing Tag", false), + acronymStyle: acronymOption(AcronymStyleOptions.Pascal) +}; +export class PhpTargetLanguage extends TargetLanguage { + public constructor() { + super("PHP", ["php"], "php"); + } + + protected getOptions(): Array> { + return _.values(phpOptions); + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PhpRenderer { + const options = getOptionValues(phpOptions, untypedOptionValues); + return new PhpRenderer(this, renderContext, options); + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + mapping.set("date", "date"); // TODO is not implemented yet + mapping.set("time", "time"); // TODO is not implemented yet + mapping.set("uuid", "uuid"); // TODO is not implemented yet + mapping.set("date-time", "date-time"); + return mapping; + } +} diff --git a/packages/quicktype-core/src/language/Php/utils.ts b/packages/quicktype-core/src/language/Php/utils.ts new file mode 100644 index 000000000..2c219178d --- /dev/null +++ b/packages/quicktype-core/src/language/Php/utils.ts @@ -0,0 +1,47 @@ +import { + allLowerWordStyle, + allUpperWordStyle, + combineWords, + escapeNonPrintableMapper, + firstUpperWordStyle, + isAscii, + isDigit, + isLetter, + splitIntoWords, + standardUnicodeHexEscape, + utf16ConcatMap, + utf16LegalizeCharacters +} from "../../support/Strings"; +import * as _ from "lodash"; + +export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); + +function isStartCharacter(codePoint: number): boolean { + if (codePoint === 0x5f) return true; // underscore + return isAscii(codePoint) && isLetter(codePoint); +} + +function isPartCharacter(codePoint: number): boolean { + return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); +} + +const legalizeName = utf16LegalizeCharacters(isPartCharacter); + +export function phpNameStyle( + startWithUpper: boolean, + upperUnderscore: boolean, + original: string, + acronymsStyle: (s: string) => string = allUpperWordStyle +): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + upperUnderscore ? allUpperWordStyle : startWithUpper ? firstUpperWordStyle : allLowerWordStyle, + upperUnderscore ? allUpperWordStyle : firstUpperWordStyle, + upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, + acronymsStyle, + upperUnderscore ? "_" : "", + isStartCharacter + ); +} From 1fa8f35df8fb87fa77afb7137e684dd9f0654051 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:00:17 -0700 Subject: [PATCH 50/80] move Objective-C to own dir --- .../ObjectiveCRenderer.ts} | 266 ++---------------- .../src/language/Objective-C/constants.ts | 82 ++++++ .../src/language/Objective-C/index.ts | 2 + .../src/language/Objective-C/language.ts | 46 +++ .../src/language/Objective-C/utils.ts | 85 ++++++ 5 files changed, 246 insertions(+), 235 deletions(-) rename packages/quicktype-core/src/language/{Objective-C.ts => Objective-C/ObjectiveCRenderer.ts} (84%) create mode 100644 packages/quicktype-core/src/language/Objective-C/constants.ts create mode 100644 packages/quicktype-core/src/language/Objective-C/index.ts create mode 100644 packages/quicktype-core/src/language/Objective-C/language.ts create mode 100644 packages/quicktype-core/src/language/Objective-C/utils.ts diff --git a/packages/quicktype-core/src/language/Objective-C.ts b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts similarity index 84% rename from packages/quicktype-core/src/language/Objective-C.ts rename to packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts index 3b46b914b..e4bd7517d 100644 --- a/packages/quicktype-core/src/language/Objective-C.ts +++ b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts @@ -1,231 +1,27 @@ import { iterableFirst, iterableSome, mapContains, mapFirst, mapSome } from "collection-utils"; -import unicode from "unicode-properties"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { camelCase, fastIsUpperCase, repeatString, stringEscape } from "../../support/Strings"; +import { assert, defined } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, Type, UnionType } from "../../Type"; +import { isAnyOrNull, matchType, nullableFromUnion } from "../../TypeUtils"; + +import { forbiddenPropertyNames, keywords } from "./constants"; +import { DEFAULT_CLASS_PREFIX, type MemoryAttribute, type objectiveCOptions } from "./language"; import { - BooleanOption, - EnumOption, - type Option, - type OptionValues, - StringOption, - getOptionValues -} from "../RendererOptions"; -import { type Sourcelike, modifySource } from "../Source"; -import { - addPrefixIfNecessary, - allLowerWordStyle, - allUpperWordStyle, - camelCase, - combineWords, - fastIsUpperCase, - firstUpperWordStyle, - repeatString, - splitIntoWords, - stringEscape, - utf16LegalizeCharacters -} from "../support/Strings"; -import { assert, defined } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, Type, UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { isAnyOrNull, matchType, nullableFromUnion } from "../TypeUtils"; - -export type MemoryAttribute = "assign" | "strong" | "copy"; -export interface OutputFeatures { - implementation: boolean; - interface: boolean; -} + forbiddenForEnumCases, + propertyNameStyle, + splitExtension, + staticEnumValuesIdentifier, + typeNameStyle +} from "./utils"; const DEBUG = false; -const DEFAULT_CLASS_PREFIX = "QT"; - -export const objcOptions = { - features: new EnumOption("features", "Interface and implementation", [ - ["all", { interface: true, implementation: true }], - ["interface", { interface: true, implementation: false }], - ["implementation", { interface: false, implementation: true }] - ]), - justTypes: new BooleanOption("just-types", "Plain types only", false), - marshallingFunctions: new BooleanOption("functions", "C-style functions", false), - classPrefix: new StringOption("class-prefix", "Class prefix", "PREFIX", DEFAULT_CLASS_PREFIX), - extraComments: new BooleanOption("extra-comments", "Extra comments", false) -}; - -export class ObjectiveCTargetLanguage extends TargetLanguage { - public constructor() { - super("Objective-C", ["objc", "objective-c", "objectivec"], "m"); - } - - protected getOptions(): Array> { - return [ - objcOptions.justTypes, - objcOptions.classPrefix, - objcOptions.features, - objcOptions.extraComments, - objcOptions.marshallingFunctions - ]; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ObjectiveCRenderer { - return new ObjectiveCRenderer(this, renderContext, getOptionValues(objcOptions, untypedOptionValues)); - } -} - -function typeNameStyle(prefix: string, original: string): string { - const words = splitIntoWords(original); - const result = combineWords( - words, - legalizeName, - firstUpperWordStyle, - firstUpperWordStyle, - allUpperWordStyle, - allUpperWordStyle, - "", - isStartCharacter - ); - return addPrefixIfNecessary(prefix, result); -} - -function propertyNameStyle(original: string, isBool = false): string { - // Objective-C developers are uncomfortable with property "id" - // so we use an alternate name in this special case. - if (original === "id") { - original = "identifier"; - } - - let words = splitIntoWords(original); - - if (isBool) { - if (words.length === 0) { - words = [{ word: "flag", isAcronym: false }]; - } else if (!words[0].isAcronym && !booleanPrefixes.includes(words[0].word)) { - words = [{ word: "is", isAcronym: false }, ...words]; - } - } - - // Properties cannot even begin with any of the forbidden names - // For example, properies named new* are treated differently by ARC - if (words.length > 0 && forbiddenPropertyNames.includes(words[0].word)) { - words = [{ word: "the", isAcronym: false }, ...words]; - } - - return combineWords( - words, - legalizeName, - allLowerWordStyle, - firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle, - "", - isStartCharacter - ); -} - -const keywords = [ - /* - "_Bool", - "_Complex", - "_Imaginary", - */ - "asm", - "atomic", - "auto", - "bool", - "break", - "case", - "char", - "const", - "continue", - "default", - "do", - "double", - "else", - "enum", - "extern", - "false", - "float", - "for", - "goto", - "if", - "inline", - "int", - "long", - "nil", - "nonatomic", - "register", - "restrict", - "retain", - "return", - "short", - "signed", - "sizeof", - "static", - "struct", - "switch", - "typedef", - "typeof", - "true", - "union", - "unsigned", - "void", - "volatile", - "while" -]; - -const forbiddenPropertyNames = [ - "id", - "hash", - "description", - "init", - "copy", - "mutableCopy", - "superclass", - "debugDescription", - "new" -]; - -const booleanPrefixes = [ - "is", - "are", - "were", - "was", - "will", - "all", - "some", - "many", - "has", - "have", - "had", - "does", - "do", - "requires", - "require", - "needs", - "need" -]; - -function isStartCharacter(utf16Unit: number): boolean { - return unicode.isAlphabetic(utf16Unit) || utf16Unit === 0x5f; // underscore -} - -function isPartCharacter(utf16Unit: number): boolean { - const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); -} - -const legalizeName = utf16LegalizeCharacters(isPartCharacter); - -const staticEnumValuesIdentifier = "values"; -const forbiddenForEnumCases = ["new", staticEnumValuesIdentifier]; - -function splitExtension(filename: string): [string, string] { - const i = filename.lastIndexOf("."); - const extension = i !== -1 ? filename.split(".").pop() : "m"; - filename = i !== -1 ? filename.slice(0, i) : filename; - return [filename, extension ?? "m"]; -} export class ObjectiveCRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; @@ -235,7 +31,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues ) { super(targetLanguage, renderContext); @@ -259,12 +55,12 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return name.slice(0, firstNonUpper - 1); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return keywords; } protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { - return { names: forbiddenPropertyNames, includeGlobalForbidden: true }; + return { names: forbiddenPropertyNames as unknown as string[], includeGlobalForbidden: true }; } protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { @@ -1087,15 +883,15 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { protected emitMapFunction(): void { if (this.needsMap) { this.emitMultiline(`static id map(id collection, id (^f)(id value)) { - id result = nil; - if ([collection isKindOfClass:NSArray.class]) { - result = [NSMutableArray arrayWithCapacity:[collection count]]; - for (id x in collection) [result addObject:f(x)]; - } else if ([collection isKindOfClass:NSDictionary.class]) { - result = [NSMutableDictionary dictionaryWithCapacity:[collection count]]; - for (id key in collection) [result setObject:f([collection objectForKey:key]) forKey:key]; - } - return result; + id result = nil; + if ([collection isKindOfClass:NSArray.class]) { + result = [NSMutableArray arrayWithCapacity:[collection count]]; + for (id x in collection) [result addObject:f(x)]; + } else if ([collection isKindOfClass:NSDictionary.class]) { + result = [NSMutableDictionary dictionaryWithCapacity:[collection count]]; + for (id key in collection) [result setObject:f([collection objectForKey:key]) forKey:key]; + } + return result; }`); } } diff --git a/packages/quicktype-core/src/language/Objective-C/constants.ts b/packages/quicktype-core/src/language/Objective-C/constants.ts new file mode 100644 index 000000000..84ec8f95f --- /dev/null +++ b/packages/quicktype-core/src/language/Objective-C/constants.ts @@ -0,0 +1,82 @@ +export const keywords = [ + /* + "_Bool", + "_Complex", + "_Imaginary", + */ + "asm", + "atomic", + "auto", + "bool", + "break", + "case", + "char", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extern", + "false", + "float", + "for", + "goto", + "if", + "inline", + "int", + "long", + "nil", + "nonatomic", + "register", + "restrict", + "retain", + "return", + "short", + "signed", + "sizeof", + "static", + "struct", + "switch", + "typedef", + "typeof", + "true", + "union", + "unsigned", + "void", + "volatile", + "while" +] as const; + +export const forbiddenPropertyNames = [ + "id", + "hash", + "description", + "init", + "copy", + "mutableCopy", + "superclass", + "debugDescription", + "new" +] as const; + +export const booleanPrefixes = [ + "is", + "are", + "were", + "was", + "will", + "all", + "some", + "many", + "has", + "have", + "had", + "does", + "do", + "requires", + "require", + "needs", + "need" +] as const; diff --git a/packages/quicktype-core/src/language/Objective-C/index.ts b/packages/quicktype-core/src/language/Objective-C/index.ts new file mode 100644 index 000000000..46926c8c6 --- /dev/null +++ b/packages/quicktype-core/src/language/Objective-C/index.ts @@ -0,0 +1,2 @@ +export { ObjectiveCTargetLanguage, objectiveCOptions } from "./language"; +export { ObjectiveCRenderer } from "./ObjectiveCRenderer"; diff --git a/packages/quicktype-core/src/language/Objective-C/language.ts b/packages/quicktype-core/src/language/Objective-C/language.ts new file mode 100644 index 000000000..9c4984df6 --- /dev/null +++ b/packages/quicktype-core/src/language/Objective-C/language.ts @@ -0,0 +1,46 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { ObjectiveCRenderer } from "./ObjectiveCRenderer"; + +export type MemoryAttribute = "assign" | "strong" | "copy"; +export interface OutputFeatures { + implementation: boolean; + interface: boolean; +} + +export const DEFAULT_CLASS_PREFIX = "QT"; + +export const objectiveCOptions = { + features: new EnumOption("features", "Interface and implementation", [ + ["all", { interface: true, implementation: true }], + ["interface", { interface: true, implementation: false }], + ["implementation", { interface: false, implementation: true }] + ]), + justTypes: new BooleanOption("just-types", "Plain types only", false), + marshallingFunctions: new BooleanOption("functions", "C-style functions", false), + classPrefix: new StringOption("class-prefix", "Class prefix", "PREFIX", DEFAULT_CLASS_PREFIX), + extraComments: new BooleanOption("extra-comments", "Extra comments", false) +}; + +export class ObjectiveCTargetLanguage extends TargetLanguage { + public constructor() { + super("Objective-C", ["objc", "objective-c", "objectivec"], "m"); + } + + protected getOptions(): Array> { + return [ + objectiveCOptions.justTypes, + objectiveCOptions.classPrefix, + objectiveCOptions.features, + objectiveCOptions.extraComments, + objectiveCOptions.marshallingFunctions + ]; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ObjectiveCRenderer { + return new ObjectiveCRenderer(this, renderContext, getOptionValues(objectiveCOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/Objective-C/utils.ts b/packages/quicktype-core/src/language/Objective-C/utils.ts new file mode 100644 index 000000000..fa3929597 --- /dev/null +++ b/packages/quicktype-core/src/language/Objective-C/utils.ts @@ -0,0 +1,85 @@ +import { + splitIntoWords, + combineWords, + firstUpperWordStyle, + allUpperWordStyle, + allLowerWordStyle, + utf16LegalizeCharacters, + addPrefixIfNecessary +} from "../../support/Strings"; + +import unicode from "unicode-properties"; +import { booleanPrefixes, forbiddenPropertyNames } from "./constants"; + +export function typeNameStyle(prefix: string, original: string): string { + const words = splitIntoWords(original); + const result = combineWords( + words, + legalizeName, + firstUpperWordStyle, + firstUpperWordStyle, + allUpperWordStyle, + allUpperWordStyle, + "", + isStartCharacter + ); + return addPrefixIfNecessary(prefix, result); +} + +export function propertyNameStyle(original: string, isBool = false): string { + // Objective-C developers are uncomfortable with property "id" + // so we use an alternate name in this special case. + if (original === "id") { + original = "identifier"; + } + + let words = splitIntoWords(original); + + if (isBool) { + if (words.length === 0) { + words = [{ word: "flag", isAcronym: false }]; + // @ts-expect-error needs strict type + } else if (!words[0].isAcronym && booleanPrefixes.indexOf(words[0].word) < 0) { + words = [{ word: "is", isAcronym: false }, ...words]; + } + } + + // Properties cannot even begin with any of the forbidden names + // For example, properies named new* are treated differently by ARC + // @ts-expect-error needs strict type + if (words.length > 0 && forbiddenPropertyNames.indexOf(words[0].word) >= 0) { + words = [{ word: "the", isAcronym: false }, ...words]; + } + + return combineWords( + words, + legalizeName, + allLowerWordStyle, + firstUpperWordStyle, + allLowerWordStyle, + allUpperWordStyle, + "", + isStartCharacter + ); +} + +function isStartCharacter(utf16Unit: number): boolean { + return unicode.isAlphabetic(utf16Unit) || utf16Unit === 0x5f; // underscore +} + +function isPartCharacter(utf16Unit: number): boolean { + const category: string = unicode.getCategory(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); +} + +const legalizeName = utf16LegalizeCharacters(isPartCharacter); + +export const staticEnumValuesIdentifier = "values"; +export const forbiddenForEnumCases = ["new", staticEnumValuesIdentifier]; + +export function splitExtension(filename: string): [string, string] { + const i = filename.lastIndexOf("."); + const extension = i !== -1 ? filename.split(".").pop() : "m"; + filename = i !== -1 ? filename.slice(0, i) : filename; + return [filename, extension === undefined ? "m" : extension]; +} From a9fd2c143ac2426b5b9efe6d1db0f0f34c314c70 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:09:29 -0700 Subject: [PATCH 51/80] move Kotlin to own dir --- .../quicktype-core/src/language/Kotlin.ts | 1129 ----------------- .../language/Kotlin/KotlinJacksonRenderer.ts | 293 +++++ .../language/Kotlin/KotlinKlaxonRenderer.ts | 306 +++++ .../src/language/Kotlin/KotlinRenderer.ts | 300 +++++ .../src/language/Kotlin/KotlinXRenderer.ts | 121 ++ .../src/language/Kotlin/constants.ts | 51 + .../src/language/Kotlin/index.ts | 5 + .../src/language/Kotlin/language.ts | 70 + .../src/language/Kotlin/utils.ts | 54 + 9 files changed, 1200 insertions(+), 1129 deletions(-) delete mode 100644 packages/quicktype-core/src/language/Kotlin.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/KotlinKlaxonRenderer.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/KotlinRenderer.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/constants.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/index.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/language.ts create mode 100644 packages/quicktype-core/src/language/Kotlin/utils.ts diff --git a/packages/quicktype-core/src/language/Kotlin.ts b/packages/quicktype-core/src/language/Kotlin.ts deleted file mode 100644 index d2f759506..000000000 --- a/packages/quicktype-core/src/language/Kotlin.ts +++ /dev/null @@ -1,1129 +0,0 @@ -import { arrayIntercalate, iterableSome } from "collection-utils"; - -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; -import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; -import { - allLowerWordStyle, - allUpperWordStyle, - camelCase, - combineWords, - escapeNonPrintableMapper, - firstUpperWordStyle, - intToHex, - isDigit, - isLetterOrUnderscore, - isNumeric, - isPrintable, - legalizeCharacters, - splitIntoWords, - utf32ConcatMap -} from "../support/Strings"; -import { assertNever, mustNotHappen } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { - ArrayType, - type ClassProperty, - ClassType, - type EnumType, - MapType, - type ObjectType, - type PrimitiveType, - type Type, - UnionType -} from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export enum Framework { - None = "None", - Jackson = "Jackson", - Klaxon = "Klaxon", - KotlinX = "KotlinX" -} - -export const kotlinOptions = { - framework: new EnumOption( - "framework", - "Serialization framework", - [ - ["just-types", Framework.None], - ["jackson", Framework.Jackson], - ["klaxon", Framework.Klaxon], - ["kotlinx", Framework.KotlinX] - ], - "klaxon" - ), - acronymStyle: acronymOption(AcronymStyleOptions.Pascal), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") -}; - -export class KotlinTargetLanguage extends TargetLanguage { - public constructor() { - super("Kotlin", ["kotlin"], "kt"); - } - - protected getOptions(): Array> { - return [kotlinOptions.framework, kotlinOptions.acronymStyle, kotlinOptions.packageName]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { - const options = getOptionValues(kotlinOptions, untypedOptionValues); - - switch (options.framework) { - case Framework.None: - return new KotlinRenderer(this, renderContext, options); - case Framework.Jackson: - return new KotlinJacksonRenderer(this, renderContext, options); - case Framework.Klaxon: - return new KotlinKlaxonRenderer(this, renderContext, options); - case Framework.KotlinX: - return new KotlinXRenderer(this, renderContext, options); - default: - return assertNever(options.framework); - } - } -} - -const keywords = [ - "package", - "as", - "typealias", - "class", - "this", - "super", - "val", - "var", - "fun", - "for", - "null", - "true", - "false", - "is", - "in", - "throw", - "return", - "break", - "continue", - "object", - "if", - "try", - "else", - "while", - "do", - "when", - "interface", - "typeof", - "klaxon", - "toJson", - "Any", - "Boolean", - "Double", - "Float", - "Long", - "Int", - "Short", - "System", - "Byte", - "String", - "Array", - "List", - "Map", - "Enum", - "Class", - "JsonObject", - "JsonValue", - "Converter", - "Klaxon" -]; - -function isPartCharacter(codePoint: number): boolean { - return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); -} - -function isStartCharacter(codePoint: number): boolean { - return isPartCharacter(codePoint) && !isDigit(codePoint); -} - -const legalizeName = legalizeCharacters(isPartCharacter); - -function kotlinNameStyle( - isUpper: boolean, - original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle -): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - isUpper ? firstUpperWordStyle : allLowerWordStyle, - firstUpperWordStyle, - isUpper ? allUpperWordStyle : allLowerWordStyle, - acronymsStyle, - "", - isStartCharacter - ); -} - -function unicodeEscape(codePoint: number): string { - return "\\u" + intToHex(codePoint, 4); -} - -// eslint-disable-next-line @typescript-eslint/naming-convention -const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); - -function stringEscape(s: string): string { - // "$this" is a template string in Kotlin so we have to escape $ - return _stringEscape(s).replace(/\$/g, "\\$"); -} - -export class KotlinRenderer extends ConvenienceRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - protected readonly _kotlinOptions: OptionValues - ) { - super(targetLanguage, renderContext); - } - - protected forbiddenNamesForGlobalNamespace(): string[] { - return keywords; - } - - protected forbiddenForObjectProperties(_o: ObjectType, _classNamed: Name): ForbiddenWordsInfo { - return { names: [], includeGlobalForbidden: true }; - } - - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { - return { names: [], includeGlobalForbidden: true }; - } - - protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { - return { names: [], includeGlobalForbidden: false }; - } - - protected topLevelNameStyle(rawName: string): string { - return kotlinNameStyle(true, rawName); - } - - protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); - } - - protected namerForObjectProperty(): Namer { - return funPrefixNamer("lower", s => kotlinNameStyle(false, s, acronymStyle(this._kotlinOptions.acronymStyle))); - } - - protected makeUnionMemberNamer(): Namer { - return funPrefixNamer("upper", s => kotlinNameStyle(true, s) + "Value"); - } - - protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); - } - - protected emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); - } - - protected emitBlock(line: Sourcelike, f: () => void, delimiter: "curly" | "paren" | "lambda" = "curly"): void { - const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" ? ["(", ")"] : ["{", "})"]; - this.emitLine(line, " ", open); - this.indent(f); - this.emitLine(close); - } - - protected anySourceType(optional: string): Sourcelike { - return ["Any", optional]; - } - - // (asarazan): I've broken out the following two functions - // because some renderers, such as kotlinx, can cope with `any`, while some get mad. - protected arrayType(arrayType: ArrayType, withIssues = false, _noOptional = false): Sourcelike { - return ["List<", this.kotlinType(arrayType.items, withIssues), ">"]; - } - - protected mapType(mapType: MapType, withIssues = false, _noOptional = false): Sourcelike { - return ["Map"]; - } - - protected kotlinType(t: Type, withIssues = false, noOptional = false): Sourcelike { - const optional = noOptional ? "" : "?"; - return matchType( - t, - _anyType => { - return maybeAnnotated(withIssues, anyTypeIssueAnnotation, this.anySourceType(optional)); - }, - _nullType => { - return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(optional)); - }, - _boolType => "Boolean", - _integerType => "Long", - _doubleType => "Double", - _stringType => "String", - arrayType => this.arrayType(arrayType, withIssues), - classType => this.nameForNamedType(classType), - mapType => this.mapType(mapType, withIssues), - enumType => this.nameForNamedType(enumType), - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) return [this.kotlinType(nullable, withIssues), optional]; - return this.nameForNamedType(unionType); - } - ); - } - - protected emitUsageHeader(): void { - // To be overridden - } - - protected emitHeader(): void { - if (this.leadingComments !== undefined) { - this.emitComments(this.leadingComments); - } else { - this.emitUsageHeader(); - } - - this.ensureBlankLine(); - this.emitLine("package ", this._kotlinOptions.packageName); - this.ensureBlankLine(); - } - - protected emitTopLevelPrimitive(t: PrimitiveType, name: Name): void { - const elementType = this.kotlinType(t); - this.emitLine(["typealias ", name, " = ", elementType, ""]); - } - - protected emitTopLevelArray(t: ArrayType, name: Name): void { - const elementType = this.kotlinType(t.items); - this.emitLine(["typealias ", name, " = ArrayList<", elementType, ">"]); - } - - protected emitTopLevelMap(t: MapType, name: Name): void { - const elementType = this.kotlinType(t.values); - this.emitLine(["typealias ", name, " = HashMap"]); - } - - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { - this.emitDescription(this.descriptionForType(c)); - this.emitClassAnnotations(c, className); - this.emitLine("class ", className, "()"); - } - - protected emitClassDefinition(c: ClassType, className: Name): void { - if (c.getProperties().size === 0) { - this.emitEmptyClassDefinition(c, className); - return; - } - - const kotlinType = (p: ClassProperty): Sourcelike => { - if (p.isOptional) { - return [this.kotlinType(p.type, true, true), "?"]; - } else { - return this.kotlinType(p.type, true); - } - }; - - this.emitDescription(this.descriptionForType(c)); - this.emitClassAnnotations(c, className); - this.emitLine("data class ", className, " ("); - this.indent(() => { - let count = c.getProperties().size; - let first = true; - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - const nullable = p.type.kind === "union" && nullableFromUnion(p.type as UnionType) !== null; - const nullableOrOptional = p.isOptional || p.type.kind === "null" || nullable; - const last = --count === 0; - let meta: Array<() => void> = []; - - const description = this.descriptionForClassProperty(c, jsonName); - if (description !== undefined) { - meta.push(() => this.emitDescription(description)); - } - - this.renameAttribute(name, jsonName, !nullableOrOptional, meta); - - if (meta.length > 0 && !first) { - this.ensureBlankLine(); - } - - for (const emit of meta) { - emit(); - } - - this.emitLine("val ", name, ": ", kotlinType(p), nullableOrOptional ? " = null" : "", last ? "" : ","); - - if (meta.length > 0 && !last) { - this.ensureBlankLine(); - } - - first = false; - }); - }); - - this.emitClassDefinitionMethods(c, className); - } - - protected emitClassDefinitionMethods(_c: ClassType, _className: Name): void { - this.emitLine(")"); - } - - protected emitClassAnnotations(_c: Type, _className: Name): void { - // to be overridden - } - - protected renameAttribute(_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>): void { - // to be overridden - } - - protected emitEnumDefinition(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - - this.emitBlock(["enum class ", enumName], () => { - let count = e.cases.size; - this.forEachEnumCase(e, "none", name => { - this.emitLine(name, --count === 0 ? "" : ","); - }); - }); - } - - protected emitUnionDefinition(u: UnionType, unionName: Name): void { - function sortBy(t: Type): string { - const kind = t.kind; - if (kind === "class") return kind; - return "_" + kind; - } - - this.emitDescription(this.descriptionForType(u)); - - const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); - this.emitClassAnnotations(u, unionName); - this.emitBlock(["sealed class ", unionName], () => { - { - let table: Sourcelike[][] = []; - this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { - table.push([ - ["class ", name, "(val value: ", this.kotlinType(t), ")"], - [" : ", unionName, "()"] - ]); - }); - if (maybeNull !== null) { - table.push([ - ["class ", this.nameForUnionMember(u, maybeNull), "()"], - [" : ", unionName, "()"] - ]); - } - - this.emitTable(table); - } - - this.emitUnionDefinitionMethods(u, nonNulls, maybeNull, unionName); - }); - } - - protected emitUnionDefinitionMethods( - _u: UnionType, - _nonNulls: ReadonlySet, - _maybeNull: PrimitiveType | null, - _unionName: Name - ): void { - // to be overridden - } - - protected emitSourceStructure(): void { - this.emitHeader(); - - // Top-level arrays, maps - this.forEachTopLevel("leading", (t, name) => { - if (t instanceof ArrayType) { - this.emitTopLevelArray(t, name); - } else if (t instanceof MapType) { - this.emitTopLevelMap(t, name); - } else if (t.isPrimitive()) { - this.emitTopLevelPrimitive(t, name); - } - }); - - this.forEachNamedType( - "leading-and-interposing", - (c: ClassType, n: Name) => this.emitClassDefinition(c, n), - (e, n) => this.emitEnumDefinition(e, n), - (u, n) => this.emitUnionDefinition(u, n) - ); - } -} - -export class KotlinKlaxonRenderer extends KotlinRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - _kotlinOptions: OptionValues - ) { - super(targetLanguage, renderContext, _kotlinOptions); - } - - private unionMemberFromJsonValue(t: Type, e: Sourcelike): Sourcelike { - return matchType( - t, - _anyType => [e, ".inside"], - _nullType => "null", - _boolType => [e, ".boolean"], - _integerType => ["(", e, ".int?.toLong() ?: ", e, ".longValue)"], - _doubleType => [e, ".double"], - _stringType => [e, ".string"], - arrayType => [e, ".array?.let { klaxon.parseFromJsonArray<", this.kotlinType(arrayType.items), ">(it) }"], - _classType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], - _mapType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], - enumType => [e, ".string?.let { ", this.kotlinType(enumType), ".fromValue(it) }"], - _unionType => mustNotHappen() - ); - } - - private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { - return matchType( - t, - _anyType => "is Any", - _nullType => "null", - _boolType => "is Boolean", - _integerType => "is Int, is Long", - _doubleType => "is Double", - _stringType => "is String", - _arrayType => "is JsonArray<*>", - // These could be stricter, but for now we don't allow maps - // and objects in the same union - _classType => "is JsonObject", - _mapType => "is JsonObject", - // This could be stricter, but for now we don't allow strings - // and enums in the same union - _enumType => "is String", - _unionType => mustNotHappen() - ); - } - - protected emitUsageHeader(): void { - this.emitLine("// To parse the JSON, install Klaxon and do:"); - this.emitLine("//"); - this.forEachTopLevel("none", (_, name) => { - this.emitLine("// val ", modifySource(camelCase, name), " = ", name, ".fromJson(jsonString)"); - }); - } - - protected emitHeader(): void { - super.emitHeader(); - - this.emitLine("import com.beust.klaxon.*"); - - const hasUnions = iterableSome( - this.typeGraph.allNamedTypes(), - t => t instanceof UnionType && nullableFromUnion(t) === null - ); - const hasEmptyObjects = iterableSome( - this.typeGraph.allNamedTypes(), - c => c instanceof ClassType && c.getProperties().size === 0 - ); - if (hasUnions || this.haveEnums || hasEmptyObjects) { - this.emitGenericConverter(); - } - - let converters: Sourcelike[][] = []; - if (hasEmptyObjects) { - converters.push([[".convert(JsonObject::class,"], [" { it.obj!! },"], [" { it.toJsonString() })"]]); - } - - this.forEachEnum("none", (_, name) => { - converters.push([ - [".convert(", name, "::class,"], - [" { ", name, ".fromValue(it.string!!) },"], - [' { "\\"${it.value}\\"" })'] - ]); - }); - this.forEachUnion("none", (_, name) => { - converters.push([ - [".convert(", name, "::class,"], - [" { ", name, ".fromJson(it) },"], - [" { it.toJson() }, true)"] - ]); - }); - - this.ensureBlankLine(); - this.emitLine("private val klaxon = Klaxon()"); - if (converters.length > 0) { - this.indent(() => this.emitTable(converters)); - } - } - - protected emitTopLevelArray(t: ArrayType, name: Name): void { - const elementType = this.kotlinType(t.items); - this.emitBlock( - ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], - () => { - this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitLine( - "public fun fromJson(json: String) = ", - name, - "(klaxon.parseArray<", - elementType, - ">(json)!!)" - ); - }); - } - ); - } - - protected emitTopLevelMap(t: MapType, name: Name): void { - const elementType = this.kotlinType(t.values); - this.emitBlock( - [ - "class ", - name, - "(elements: Map) : HashMap(elements)" - ], - () => { - this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitBlock( - ["public fun fromJson(json: String) = ", name], - () => { - this.emitLine( - "klaxon.parseJsonObject(java.io.StringReader(json)) as Map" - ); - }, - "paren" - ); - }); - } - ); - } - - private klaxonRenameAttribute(propName: Name, jsonName: string, ignore = false): Sourcelike | undefined { - const escapedName = stringEscape(jsonName); - const namesDiffer = this.sourcelikeToString(propName) !== escapedName; - const properties: Sourcelike[] = []; - if (namesDiffer) { - properties.push(['name = "', escapedName, '"']); - } - - if (ignore) { - properties.push("ignored = true"); - } - - return properties.length === 0 ? undefined : ["@Json(", arrayIntercalate(", ", properties), ")"]; - } - - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { - this.emitDescription(this.descriptionForType(c)); - - this.emitLine("typealias ", className, " = JsonObject"); - } - - protected emitClassDefinitionMethods(c: ClassType, className: Name): void { - const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); - if (isTopLevel) { - this.emitBlock(")", () => { - this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitLine("public fun fromJson(json: String) = klaxon.parse<", className, ">(json)"); - }); - }); - } else { - this.emitLine(")"); - } - } - - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): void { - const rename = this.klaxonRenameAttribute(name, jsonName); - if (rename !== undefined) { - meta.push(() => this.emitLine(rename)); - } - } - - protected emitEnumDefinition(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - - this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { - let count = e.cases.size; - this.forEachEnumCase(e, "none", (name, json) => { - this.emitLine(name, `("${stringEscape(json)}")`, --count === 0 ? ";" : ","); - }); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitBlock(["public fun fromValue(value: String): ", enumName, " = when (value)"], () => { - let table: Sourcelike[][] = []; - this.forEachEnumCase(e, "none", (name, json) => { - table.push([[`"${stringEscape(json)}"`], [" -> ", name]]); - }); - table.push([["else"], [" -> throw IllegalArgumentException()"]]); - this.emitTable(table); - }); - }); - }); - } - - private emitGenericConverter(): void { - this.ensureBlankLine(); - this.emitLine( - "private fun Klaxon.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonValue) -> T, toJson: (T) -> String, isUnion: Boolean = false) =" - ); - this.indent(() => { - this.emitLine("this.converter(object: Converter {"); - this.indent(() => { - this.emitLine('@Suppress("UNCHECKED_CAST")'); - this.emitTable([ - ["override fun toJson(value: Any)", " = toJson(value as T)"], - ["override fun fromJson(jv: JsonValue)", " = fromJson(jv) as Any"], - [ - "override fun canConvert(cls: Class<*>)", - " = cls == k.java || (isUnion && cls.superclass == k.java)" - ] - ]); - }); - this.emitLine("})"); - }); - } - - protected emitUnionDefinitionMethods( - u: UnionType, - nonNulls: ReadonlySet, - maybeNull: PrimitiveType | null, - unionName: Name - ): void { - this.ensureBlankLine(); - this.emitLine("public fun toJson(): String = klaxon.toJsonString(when (this) {"); - this.indent(() => { - let toJsonTable: Sourcelike[][] = []; - this.forEachUnionMember(u, nonNulls, "none", null, name => { - toJsonTable.push([["is ", name], [" -> this.value"]]); - }); - if (maybeNull !== null) { - const name = this.nameForUnionMember(u, maybeNull); - toJsonTable.push([["is ", name], [' -> "null"']]); - } - - this.emitTable(toJsonTable); - }); - this.emitLine("})"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitLine("public fun fromJson(jv: JsonValue): ", unionName, " = when (jv.inside) {"); - this.indent(() => { - let table: Sourcelike[][] = []; - this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { - table.push([ - [this.unionMemberJsonValueGuard(t, "jv.inside")], - [" -> ", name, "(", this.unionMemberFromJsonValue(t, "jv"), "!!)"] - ]); - }); - if (maybeNull !== null) { - const name = this.nameForUnionMember(u, maybeNull); - table.push([[this.unionMemberJsonValueGuard(maybeNull, "jv.inside")], [" -> ", name, "()"]]); - } - - table.push([["else"], [" -> throw IllegalArgumentException()"]]); - this.emitTable(table); - }); - this.emitLine("}"); - }); - } -} - -export class KotlinJacksonRenderer extends KotlinRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - _kotlinOptions: OptionValues - ) { - super(targetLanguage, renderContext, _kotlinOptions); - } - - private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { - return matchType( - t, - _anyType => "is Any", - _nullType => "null", - _boolType => "is BooleanNode", - _integerType => "is IntNode, is LongNode", - _doubleType => "is DoubleNode", - _stringType => "is TextNode", - _arrayType => "is ArrayNode", - // These could be stricter, but for now we don't allow maps - // and objects in the same union - _classType => "is ObjectNode", - _mapType => "is ObjectNode", - // This could be stricter, but for now we don't allow strings - // and enums in the same union - _enumType => "is TextNode", - _unionType => mustNotHappen() - ); - } - - protected emitUsageHeader(): void { - this.emitLine("// To parse the JSON, install jackson-module-kotlin and do:"); - this.emitLine("//"); - this.forEachTopLevel("none", (_, name) => { - this.emitLine("// val ", modifySource(camelCase, name), " = ", name, ".fromJson(jsonString)"); - }); - } - - protected emitHeader(): void { - super.emitHeader(); - - this.emitMultiline(`import com.fasterxml.jackson.annotation.* -import com.fasterxml.jackson.core.* -import com.fasterxml.jackson.databind.* -import com.fasterxml.jackson.databind.deser.std.StdDeserializer -import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.databind.node.* -import com.fasterxml.jackson.databind.ser.std.StdSerializer -import com.fasterxml.jackson.module.kotlin.*`); - - const hasUnions = iterableSome( - this.typeGraph.allNamedTypes(), - t => t instanceof UnionType && nullableFromUnion(t) === null - ); - const hasEmptyObjects = iterableSome( - this.typeGraph.allNamedTypes(), - c => c instanceof ClassType && c.getProperties().size === 0 - ); - if (hasUnions || this.haveEnums || hasEmptyObjects) { - this.emitGenericConverter(); - } - - let converters: Sourcelike[][] = []; - // if (hasEmptyObjects) { - // converters.push([["convert(JsonNode::class,"], [" { it },"], [" { writeValueAsString(it) })"]]); - // } - this.forEachEnum("none", (_, name) => { - converters.push([ - ["convert(", name, "::class,"], - [" { ", name, ".fromValue(it.asText()) },"], - [' { "\\"${it.value}\\"" })'] - ]); - }); - this.forEachUnion("none", (_, name) => { - converters.push([ - ["convert(", name, "::class,"], - [" { ", name, ".fromJson(it) },"], - [" { it.toJson() }, true)"] - ]); - }); - - this.ensureBlankLine(); - this.emitLine("val mapper = jacksonObjectMapper().apply {"); - this.indent(() => { - this.emitLine("propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE"); - this.emitLine("setSerializationInclusion(JsonInclude.Include.NON_NULL)"); - }); - - if (converters.length > 0) { - this.indent(() => this.emitTable(converters)); - } - - this.emitLine("}"); - } - - protected emitTopLevelArray(t: ArrayType, name: Name): void { - const elementType = this.kotlinType(t.items); - this.emitBlock( - ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], - () => { - this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); - }); - } - ); - } - - protected emitTopLevelMap(t: MapType, name: Name): void { - const elementType = this.kotlinType(t.values); - this.emitBlock( - [ - "class ", - name, - "(elements: Map) : HashMap(elements)" - ], - () => { - this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); - }); - } - ); - } - - private jacksonRenameAttribute( - propName: Name, - jsonName: string, - required: boolean, - ignore = false - ): Sourcelike | undefined { - const escapedName = stringEscape(jsonName); - const namesDiffer = this.sourcelikeToString(propName) !== escapedName; - const properties: Sourcelike[] = []; - const isPrefixBool = jsonName.startsWith("is"); // https://github.com/FasterXML/jackson-module-kotlin/issues/80 - const propertyOpts: Sourcelike[] = []; - - if (namesDiffer || isPrefixBool) { - propertyOpts.push('"' + escapedName + '"'); - } - - if (required) { - propertyOpts.push("required=true"); - } - - if (propertyOpts.length > 0) { - properties.push(["@get:JsonProperty(", arrayIntercalate(", ", propertyOpts), ")"]); - properties.push(["@field:JsonProperty(", arrayIntercalate(", ", propertyOpts), ")"]); - } - - if (ignore) { - properties.push("@get:JsonIgnore"); - properties.push("@field:JsonIgnore"); - } - - return properties.length === 0 ? undefined : properties; - } - - protected emitEmptyClassDefinition(c: ClassType, className: Name): void { - this.emitDescription(this.descriptionForType(c)); - - this.emitLine("typealias ", className, " = JsonNode"); - } - - protected emitClassDefinitionMethods(c: ClassType, className: Name): void { - const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); - if (isTopLevel) { - this.emitBlock(")", () => { - this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitLine("fun fromJson(json: String) = mapper.readValue<", className, ">(json)"); - }); - }); - } else { - this.emitLine(")"); - } - } - - protected renameAttribute(name: Name, jsonName: string, required: boolean, meta: Array<() => void>): void { - const rename = this.jacksonRenameAttribute(name, jsonName, required); - if (rename !== undefined) { - meta.push(() => this.emitLine(rename)); - } - } - - protected emitEnumDefinition(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - - this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { - let count = e.cases.size; - this.forEachEnumCase(e, "none", (name, json) => { - this.emitLine(name, `("${stringEscape(json)}")`, --count === 0 ? ";" : ","); - }); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitBlock(["fun fromValue(value: String): ", enumName, " = when (value)"], () => { - let table: Sourcelike[][] = []; - this.forEachEnumCase(e, "none", (name, json) => { - table.push([[`"${stringEscape(json)}"`], [" -> ", name]]); - }); - table.push([["else"], [" -> throw IllegalArgumentException()"]]); - this.emitTable(table); - }); - }); - }); - } - - private emitGenericConverter(): void { - this.ensureBlankLine(); - this.emitMultiline(` -@Suppress("UNCHECKED_CAST") -private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonNode) -> T, toJson: (T) -> String, isUnion: Boolean = false) = registerModule(SimpleModule().apply { - addSerializer(k.java as Class, object : StdSerializer(k.java as Class) { - override fun serialize(value: T, gen: JsonGenerator, provider: SerializerProvider) = gen.writeRawValue(toJson(value)) - }) - addDeserializer(k.java as Class, object : StdDeserializer(k.java as Class) { - override fun deserialize(p: JsonParser, ctxt: DeserializationContext) = fromJson(p.readValueAsTree()) - }) -})`); - } - - protected emitUnionDefinitionMethods( - u: UnionType, - nonNulls: ReadonlySet, - maybeNull: PrimitiveType | null, - unionName: Name - ): void { - this.ensureBlankLine(); - this.emitLine("fun toJson(): String = mapper.writeValueAsString(when (this) {"); - this.indent(() => { - let toJsonTable: Sourcelike[][] = []; - this.forEachUnionMember(u, nonNulls, "none", null, name => { - toJsonTable.push([["is ", name], [" -> this.value"]]); - }); - if (maybeNull !== null) { - const name = this.nameForUnionMember(u, maybeNull); - toJsonTable.push([["is ", name], [' -> "null"']]); - } - - this.emitTable(toJsonTable); - }); - this.emitLine("})"); - this.ensureBlankLine(); - this.emitBlock("companion object", () => { - this.emitLine("fun fromJson(jn: JsonNode): ", unionName, " = when (jn) {"); - this.indent(() => { - let table: Sourcelike[][] = []; - this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { - table.push([[this.unionMemberJsonValueGuard(t, "jn")], [" -> ", name, "(mapper.treeToValue(jn))"]]); - }); - if (maybeNull !== null) { - const name = this.nameForUnionMember(u, maybeNull); - table.push([[this.unionMemberJsonValueGuard(maybeNull, "jn")], [" -> ", name, "()"]]); - } - - table.push([["else"], [" -> throw IllegalArgumentException()"]]); - this.emitTable(table); - }); - this.emitLine("}"); - }); - } -} - -/** - * Currently supports simple classes, enums, and TS string unions (which are also enums). - * TODO: Union, Any, Top Level Array, Top Level Map - */ -export class KotlinXRenderer extends KotlinRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - _kotlinOptions: OptionValues - ) { - super(targetLanguage, renderContext, _kotlinOptions); - } - - protected anySourceType(optional: string): Sourcelike { - return ["JsonElement", optional]; - } - - protected arrayType(arrayType: ArrayType, withIssues = false, noOptional = false): Sourcelike { - const valType = this.kotlinType(arrayType.items, withIssues, true); - const name = this.sourcelikeToString(valType); - if (name === "JsonObject" || name === "JsonElement") { - return "JsonArray"; - } - - return super.arrayType(arrayType, withIssues, noOptional); - } - - protected mapType(mapType: MapType, withIssues = false, noOptional = false): Sourcelike { - const valType = this.kotlinType(mapType.values, withIssues, true); - const name = this.sourcelikeToString(valType); - if (name === "JsonObject" || name === "JsonElement") { - return "JsonObject"; - } - - return super.mapType(mapType, withIssues, noOptional); - } - - protected emitTopLevelMap(t: MapType, name: Name): void { - const elementType = this.kotlinType(t.values); - if (elementType === "JsonObject") { - this.emitLine(["typealias ", name, " = JsonObject"]); - } else { - super.emitTopLevelMap(t, name); - } - } - - protected emitTopLevelArray(t: ArrayType, name: Name): void { - const elementType = this.kotlinType(t.items); - this.emitLine(["typealias ", name, " = JsonArray<", elementType, ">"]); - } - - protected emitUsageHeader(): void { - this.emitLine("// To parse the JSON, install kotlin's serialization plugin and do:"); - this.emitLine("//"); - const table: Sourcelike[][] = []; - table.push(["// val ", "json", " = Json { allowStructuredMapKeys = true }"]); - this.forEachTopLevel("none", (_, name) => { - table.push([ - "// val ", - modifySource(camelCase, name), - ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)` - ]); - }); - this.emitTable(table); - } - - protected emitHeader(): void { - super.emitHeader(); - - this.emitLine("import kotlinx.serialization.*"); - this.emitLine("import kotlinx.serialization.json.*"); - this.emitLine("import kotlinx.serialization.descriptors.*"); - this.emitLine("import kotlinx.serialization.encoding.*"); - } - - protected emitClassAnnotations(_c: Type, _className: Name): void { - this.emitLine("@Serializable"); - } - - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): void { - const rename = this._rename(name, jsonName); - if (rename !== undefined) { - meta.push(() => this.emitLine(rename)); - } - } - - private _rename(propName: Name, jsonName: string): Sourcelike | undefined { - const escapedName = stringEscape(jsonName); - const namesDiffer = this.sourcelikeToString(propName) !== escapedName; - if (namesDiffer) { - return ['@SerialName("', escapedName, '")']; - } - - return undefined; - } - - protected emitEnumDefinition(e: EnumType, enumName: Name): void { - this.emitDescription(this.descriptionForType(e)); - - this.emitLine(["@Serializable"]); - this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { - let count = e.cases.size; - this.forEachEnumCase(e, "none", (name, json) => { - const jsonEnum = stringEscape(json); - this.emitLine(`@SerialName("${jsonEnum}") `, name, `("${jsonEnum}")`, --count === 0 ? ";" : ","); - }); - }); - } -} diff --git a/packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts b/packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts new file mode 100644 index 000000000..0b840946a --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts @@ -0,0 +1,293 @@ +import { arrayIntercalate, iterableSome } from "collection-utils"; + +import { type Name } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { camelCase } from "../../support/Strings"; +import { mustNotHappen } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { + type ArrayType, + ClassType, + type EnumType, + type MapType, + type PrimitiveType, + type Type, + UnionType +} from "../../Type"; +import { matchType, nullableFromUnion } from "../../TypeUtils"; + +import { KotlinRenderer } from "./KotlinRenderer"; +import { type kotlinOptions } from "./language"; +import { stringEscape } from "./utils"; + +export class KotlinJacksonRenderer extends KotlinRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + _kotlinOptions: OptionValues + ) { + super(targetLanguage, renderContext, _kotlinOptions); + } + + private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { + return matchType( + t, + _anyType => "is Any", + _nullType => "null", + _boolType => "is BooleanNode", + _integerType => "is IntNode, is LongNode", + _doubleType => "is DoubleNode", + _stringType => "is TextNode", + _arrayType => "is ArrayNode", + // These could be stricter, but for now we don't allow maps + // and objects in the same union + _classType => "is ObjectNode", + _mapType => "is ObjectNode", + // This could be stricter, but for now we don't allow strings + // and enums in the same union + _enumType => "is TextNode", + _unionType => mustNotHappen() + ); + } + + protected emitUsageHeader(): void { + this.emitLine("// To parse the JSON, install jackson-module-kotlin and do:"); + this.emitLine("//"); + this.forEachTopLevel("none", (_, name) => { + this.emitLine("// val ", modifySource(camelCase, name), " = ", name, ".fromJson(jsonString)"); + }); + } + + protected emitHeader(): void { + super.emitHeader(); + + this.emitMultiline(`import com.fasterxml.jackson.annotation.* +import com.fasterxml.jackson.core.* +import com.fasterxml.jackson.databind.* +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.node.* +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.fasterxml.jackson.module.kotlin.*`); + + const hasUnions = iterableSome( + this.typeGraph.allNamedTypes(), + t => t instanceof UnionType && nullableFromUnion(t) === null + ); + const hasEmptyObjects = iterableSome( + this.typeGraph.allNamedTypes(), + c => c instanceof ClassType && c.getProperties().size === 0 + ); + if (hasUnions || this.haveEnums || hasEmptyObjects) { + this.emitGenericConverter(); + } + + let converters: Sourcelike[][] = []; + // if (hasEmptyObjects) { + // converters.push([["convert(JsonNode::class,"], [" { it },"], [" { writeValueAsString(it) })"]]); + // } + this.forEachEnum("none", (_, name) => { + converters.push([ + ["convert(", name, "::class,"], + [" { ", name, ".fromValue(it.asText()) },"], + [' { "\\"${it.value}\\"" })'] + ]); + }); + this.forEachUnion("none", (_, name) => { + converters.push([ + ["convert(", name, "::class,"], + [" { ", name, ".fromJson(it) },"], + [" { it.toJson() }, true)"] + ]); + }); + + this.ensureBlankLine(); + this.emitLine("val mapper = jacksonObjectMapper().apply {"); + this.indent(() => { + this.emitLine("propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE"); + this.emitLine("setSerializationInclusion(JsonInclude.Include.NON_NULL)"); + }); + + if (converters.length > 0) { + this.indent(() => this.emitTable(converters)); + } + + this.emitLine("}"); + } + + protected emitTopLevelArray(t: ArrayType, name: Name): void { + const elementType = this.kotlinType(t.items); + this.emitBlock( + ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], + () => { + this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); + }); + } + ); + } + + protected emitTopLevelMap(t: MapType, name: Name): void { + const elementType = this.kotlinType(t.values); + this.emitBlock( + [ + "class ", + name, + "(elements: Map) : HashMap(elements)" + ], + () => { + this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); + }); + } + ); + } + + private jacksonRenameAttribute( + propName: Name, + jsonName: string, + required: boolean, + ignore = false + ): Sourcelike | undefined { + const escapedName = stringEscape(jsonName); + const namesDiffer = this.sourcelikeToString(propName) !== escapedName; + const properties: Sourcelike[] = []; + const isPrefixBool = jsonName.startsWith("is"); // https://github.com/FasterXML/jackson-module-kotlin/issues/80 + const propertyOpts: Sourcelike[] = []; + + if (namesDiffer || isPrefixBool) { + propertyOpts.push('"' + escapedName + '"'); + } + + if (required) { + propertyOpts.push("required=true"); + } + + if (propertyOpts.length > 0) { + properties.push(["@get:JsonProperty(", arrayIntercalate(", ", propertyOpts), ")"]); + properties.push(["@field:JsonProperty(", arrayIntercalate(", ", propertyOpts), ")"]); + } + + if (ignore) { + properties.push("@get:JsonIgnore"); + properties.push("@field:JsonIgnore"); + } + + return properties.length === 0 ? undefined : properties; + } + + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + this.emitDescription(this.descriptionForType(c)); + + this.emitLine("typealias ", className, " = JsonNode"); + } + + protected emitClassDefinitionMethods(c: ClassType, className: Name): void { + const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); + if (isTopLevel) { + this.emitBlock(")", () => { + this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitLine("fun fromJson(json: String) = mapper.readValue<", className, ">(json)"); + }); + }); + } else { + this.emitLine(")"); + } + } + + protected renameAttribute(name: Name, jsonName: string, required: boolean, meta: Array<() => void>): void { + const rename = this.jacksonRenameAttribute(name, jsonName, required); + if (rename !== undefined) { + meta.push(() => this.emitLine(rename)); + } + } + + protected emitEnumDefinition(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + + this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { + let count = e.cases.size; + this.forEachEnumCase(e, "none", (name, json) => { + this.emitLine(name, `("${stringEscape(json)}")`, --count === 0 ? ";" : ","); + }); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitBlock(["fun fromValue(value: String): ", enumName, " = when (value)"], () => { + let table: Sourcelike[][] = []; + this.forEachEnumCase(e, "none", (name, json) => { + table.push([[`"${stringEscape(json)}"`], [" -> ", name]]); + }); + table.push([["else"], [" -> throw IllegalArgumentException()"]]); + this.emitTable(table); + }); + }); + }); + } + + private emitGenericConverter(): void { + this.ensureBlankLine(); + this.emitMultiline(` +@Suppress("UNCHECKED_CAST") +private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonNode) -> T, toJson: (T) -> String, isUnion: Boolean = false) = registerModule(SimpleModule().apply { + addSerializer(k.java as Class, object : StdSerializer(k.java as Class) { + override fun serialize(value: T, gen: JsonGenerator, provider: SerializerProvider) = gen.writeRawValue(toJson(value)) + }) + addDeserializer(k.java as Class, object : StdDeserializer(k.java as Class) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext) = fromJson(p.readValueAsTree()) + }) +})`); + } + + protected emitUnionDefinitionMethods( + u: UnionType, + nonNulls: ReadonlySet, + maybeNull: PrimitiveType | null, + unionName: Name + ): void { + this.ensureBlankLine(); + this.emitLine("fun toJson(): String = mapper.writeValueAsString(when (this) {"); + this.indent(() => { + let toJsonTable: Sourcelike[][] = []; + this.forEachUnionMember(u, nonNulls, "none", null, name => { + toJsonTable.push([["is ", name], [" -> this.value"]]); + }); + if (maybeNull !== null) { + const name = this.nameForUnionMember(u, maybeNull); + toJsonTable.push([["is ", name], [' -> "null"']]); + } + + this.emitTable(toJsonTable); + }); + this.emitLine("})"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitLine("fun fromJson(jn: JsonNode): ", unionName, " = when (jn) {"); + this.indent(() => { + let table: Sourcelike[][] = []; + this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { + table.push([[this.unionMemberJsonValueGuard(t, "jn")], [" -> ", name, "(mapper.treeToValue(jn))"]]); + }); + if (maybeNull !== null) { + const name = this.nameForUnionMember(u, maybeNull); + table.push([[this.unionMemberJsonValueGuard(maybeNull, "jn")], [" -> ", name, "()"]]); + } + + table.push([["else"], [" -> throw IllegalArgumentException()"]]); + this.emitTable(table); + }); + this.emitLine("}"); + }); + } +} diff --git a/packages/quicktype-core/src/language/Kotlin/KotlinKlaxonRenderer.ts b/packages/quicktype-core/src/language/Kotlin/KotlinKlaxonRenderer.ts new file mode 100644 index 000000000..bcfaf9043 --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/KotlinKlaxonRenderer.ts @@ -0,0 +1,306 @@ +import { arrayIntercalate, iterableSome } from "collection-utils"; + +import { type Name } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { camelCase } from "../../support/Strings"; +import { mustNotHappen } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { + type ArrayType, + ClassType, + type EnumType, + type MapType, + type PrimitiveType, + type Type, + UnionType +} from "../../Type"; +import { matchType, nullableFromUnion } from "../../TypeUtils"; + +import { KotlinRenderer } from "./KotlinRenderer"; +import { type kotlinOptions } from "./language"; +import { stringEscape } from "./utils"; + +export class KotlinKlaxonRenderer extends KotlinRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + _kotlinOptions: OptionValues + ) { + super(targetLanguage, renderContext, _kotlinOptions); + } + + private unionMemberFromJsonValue(t: Type, e: Sourcelike): Sourcelike { + return matchType( + t, + _anyType => [e, ".inside"], + _nullType => "null", + _boolType => [e, ".boolean"], + _integerType => ["(", e, ".int?.toLong() ?: ", e, ".longValue)"], + _doubleType => [e, ".double"], + _stringType => [e, ".string"], + arrayType => [e, ".array?.let { klaxon.parseFromJsonArray<", this.kotlinType(arrayType.items), ">(it) }"], + _classType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], + _mapType => [e, ".obj?.let { klaxon.parseFromJsonObject<", this.kotlinType(t), ">(it) }"], + enumType => [e, ".string?.let { ", this.kotlinType(enumType), ".fromValue(it) }"], + _unionType => mustNotHappen() + ); + } + + private unionMemberJsonValueGuard(t: Type, _e: Sourcelike): Sourcelike { + return matchType( + t, + _anyType => "is Any", + _nullType => "null", + _boolType => "is Boolean", + _integerType => "is Int, is Long", + _doubleType => "is Double", + _stringType => "is String", + _arrayType => "is JsonArray<*>", + // These could be stricter, but for now we don't allow maps + // and objects in the same union + _classType => "is JsonObject", + _mapType => "is JsonObject", + // This could be stricter, but for now we don't allow strings + // and enums in the same union + _enumType => "is String", + _unionType => mustNotHappen() + ); + } + + protected emitUsageHeader(): void { + this.emitLine("// To parse the JSON, install Klaxon and do:"); + this.emitLine("//"); + this.forEachTopLevel("none", (_, name) => { + this.emitLine("// val ", modifySource(camelCase, name), " = ", name, ".fromJson(jsonString)"); + }); + } + + protected emitHeader(): void { + super.emitHeader(); + + this.emitLine("import com.beust.klaxon.*"); + + const hasUnions = iterableSome( + this.typeGraph.allNamedTypes(), + t => t instanceof UnionType && nullableFromUnion(t) === null + ); + const hasEmptyObjects = iterableSome( + this.typeGraph.allNamedTypes(), + c => c instanceof ClassType && c.getProperties().size === 0 + ); + if (hasUnions || this.haveEnums || hasEmptyObjects) { + this.emitGenericConverter(); + } + + let converters: Sourcelike[][] = []; + if (hasEmptyObjects) { + converters.push([[".convert(JsonObject::class,"], [" { it.obj!! },"], [" { it.toJsonString() })"]]); + } + + this.forEachEnum("none", (_, name) => { + converters.push([ + [".convert(", name, "::class,"], + [" { ", name, ".fromValue(it.string!!) },"], + [' { "\\"${it.value}\\"" })'] + ]); + }); + this.forEachUnion("none", (_, name) => { + converters.push([ + [".convert(", name, "::class,"], + [" { ", name, ".fromJson(it) },"], + [" { it.toJson() }, true)"] + ]); + }); + + this.ensureBlankLine(); + this.emitLine("private val klaxon = Klaxon()"); + if (converters.length > 0) { + this.indent(() => this.emitTable(converters)); + } + } + + protected emitTopLevelArray(t: ArrayType, name: Name): void { + const elementType = this.kotlinType(t.items); + this.emitBlock( + ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], + () => { + this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitLine( + "public fun fromJson(json: String) = ", + name, + "(klaxon.parseArray<", + elementType, + ">(json)!!)" + ); + }); + } + ); + } + + protected emitTopLevelMap(t: MapType, name: Name): void { + const elementType = this.kotlinType(t.values); + this.emitBlock( + [ + "class ", + name, + "(elements: Map) : HashMap(elements)" + ], + () => { + this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitBlock( + ["public fun fromJson(json: String) = ", name], + () => { + this.emitLine( + "klaxon.parseJsonObject(java.io.StringReader(json)) as Map" + ); + }, + "paren" + ); + }); + } + ); + } + + private klaxonRenameAttribute(propName: Name, jsonName: string, ignore = false): Sourcelike | undefined { + const escapedName = stringEscape(jsonName); + const namesDiffer = this.sourcelikeToString(propName) !== escapedName; + const properties: Sourcelike[] = []; + if (namesDiffer) { + properties.push(['name = "', escapedName, '"']); + } + + if (ignore) { + properties.push("ignored = true"); + } + + return properties.length === 0 ? undefined : ["@Json(", arrayIntercalate(", ", properties), ")"]; + } + + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + this.emitDescription(this.descriptionForType(c)); + + this.emitLine("typealias ", className, " = JsonObject"); + } + + protected emitClassDefinitionMethods(c: ClassType, className: Name): void { + const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); + if (isTopLevel) { + this.emitBlock(")", () => { + this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitLine("public fun fromJson(json: String) = klaxon.parse<", className, ">(json)"); + }); + }); + } else { + this.emitLine(")"); + } + } + + protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): void { + const rename = this.klaxonRenameAttribute(name, jsonName); + if (rename !== undefined) { + meta.push(() => this.emitLine(rename)); + } + } + + protected emitEnumDefinition(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + + this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { + let count = e.cases.size; + this.forEachEnumCase(e, "none", (name, json) => { + this.emitLine(name, `("${stringEscape(json)}")`, --count === 0 ? ";" : ","); + }); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitBlock(["public fun fromValue(value: String): ", enumName, " = when (value)"], () => { + let table: Sourcelike[][] = []; + this.forEachEnumCase(e, "none", (name, json) => { + table.push([[`"${stringEscape(json)}"`], [" -> ", name]]); + }); + table.push([["else"], [" -> throw IllegalArgumentException()"]]); + this.emitTable(table); + }); + }); + }); + } + + private emitGenericConverter(): void { + this.ensureBlankLine(); + this.emitLine( + "private fun Klaxon.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonValue) -> T, toJson: (T) -> String, isUnion: Boolean = false) =" + ); + this.indent(() => { + this.emitLine("this.converter(object: Converter {"); + this.indent(() => { + this.emitLine('@Suppress("UNCHECKED_CAST")'); + this.emitTable([ + ["override fun toJson(value: Any)", " = toJson(value as T)"], + ["override fun fromJson(jv: JsonValue)", " = fromJson(jv) as Any"], + [ + "override fun canConvert(cls: Class<*>)", + " = cls == k.java || (isUnion && cls.superclass == k.java)" + ] + ]); + }); + this.emitLine("})"); + }); + } + + protected emitUnionDefinitionMethods( + u: UnionType, + nonNulls: ReadonlySet, + maybeNull: PrimitiveType | null, + unionName: Name + ): void { + this.ensureBlankLine(); + this.emitLine("public fun toJson(): String = klaxon.toJsonString(when (this) {"); + this.indent(() => { + let toJsonTable: Sourcelike[][] = []; + this.forEachUnionMember(u, nonNulls, "none", null, name => { + toJsonTable.push([["is ", name], [" -> this.value"]]); + }); + if (maybeNull !== null) { + const name = this.nameForUnionMember(u, maybeNull); + toJsonTable.push([["is ", name], [' -> "null"']]); + } + + this.emitTable(toJsonTable); + }); + this.emitLine("})"); + this.ensureBlankLine(); + this.emitBlock("companion object", () => { + this.emitLine("public fun fromJson(jv: JsonValue): ", unionName, " = when (jv.inside) {"); + this.indent(() => { + let table: Sourcelike[][] = []; + this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { + table.push([ + [this.unionMemberJsonValueGuard(t, "jv.inside")], + [" -> ", name, "(", this.unionMemberFromJsonValue(t, "jv"), "!!)"] + ]); + }); + if (maybeNull !== null) { + const name = this.nameForUnionMember(u, maybeNull); + table.push([[this.unionMemberJsonValueGuard(maybeNull, "jv.inside")], [" -> ", name, "()"]]); + } + + table.push([["else"], [" -> throw IllegalArgumentException()"]]); + this.emitTable(table); + }); + this.emitLine("}"); + }); + } +} diff --git a/packages/quicktype-core/src/language/Kotlin/KotlinRenderer.ts b/packages/quicktype-core/src/language/Kotlin/KotlinRenderer.ts new file mode 100644 index 000000000..d7e5abaaa --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/KotlinRenderer.ts @@ -0,0 +1,300 @@ +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { acronymStyle } from "../../support/Acronyms"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + type ClassType, + type EnumType, + MapType, + type ObjectType, + type PrimitiveType, + type Type, + type UnionType +} from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { type kotlinOptions } from "./language"; +import { kotlinNameStyle } from "./utils"; + +export class KotlinRenderer extends ConvenienceRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + protected readonly _kotlinOptions: OptionValues + ) { + super(targetLanguage, renderContext); + } + + protected forbiddenNamesForGlobalNamespace(): readonly string[] { + return keywords; + } + + protected forbiddenForObjectProperties(_o: ObjectType, _classNamed: Name): ForbiddenWordsInfo { + return { names: [], includeGlobalForbidden: true }; + } + + protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + return { names: [], includeGlobalForbidden: true }; + } + + protected forbiddenForUnionMembers(_u: UnionType, _unionName: Name): ForbiddenWordsInfo { + return { names: [], includeGlobalForbidden: false }; + } + + protected topLevelNameStyle(rawName: string): string { + return kotlinNameStyle(true, rawName); + } + + protected makeNamedTypeNamer(): Namer { + return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); + } + + protected namerForObjectProperty(): Namer { + return funPrefixNamer("lower", s => kotlinNameStyle(false, s, acronymStyle(this._kotlinOptions.acronymStyle))); + } + + protected makeUnionMemberNamer(): Namer { + return funPrefixNamer("upper", s => kotlinNameStyle(true, s) + "Value"); + } + + protected makeEnumCaseNamer(): Namer { + return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); + } + + protected emitDescriptionBlock(lines: Sourcelike[]): void { + this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + } + + protected emitBlock(line: Sourcelike, f: () => void, delimiter: "curly" | "paren" | "lambda" = "curly"): void { + const [open, close] = delimiter === "curly" ? ["{", "}"] : delimiter === "paren" ? ["(", ")"] : ["{", "})"]; + this.emitLine(line, " ", open); + this.indent(f); + this.emitLine(close); + } + + protected anySourceType(optional: string): Sourcelike { + return ["Any", optional]; + } + + // (asarazan): I've broken out the following two functions + // because some renderers, such as kotlinx, can cope with `any`, while some get mad. + protected arrayType(arrayType: ArrayType, withIssues = false, _noOptional = false): Sourcelike { + return ["List<", this.kotlinType(arrayType.items, withIssues), ">"]; + } + + protected mapType(mapType: MapType, withIssues = false, _noOptional = false): Sourcelike { + return ["Map"]; + } + + protected kotlinType(t: Type, withIssues = false, noOptional = false): Sourcelike { + const optional = noOptional ? "" : "?"; + return matchType( + t, + _anyType => { + return maybeAnnotated(withIssues, anyTypeIssueAnnotation, this.anySourceType(optional)); + }, + _nullType => { + return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(optional)); + }, + _boolType => "Boolean", + _integerType => "Long", + _doubleType => "Double", + _stringType => "String", + arrayType => this.arrayType(arrayType, withIssues), + classType => this.nameForNamedType(classType), + mapType => this.mapType(mapType, withIssues), + enumType => this.nameForNamedType(enumType), + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) return [this.kotlinType(nullable, withIssues), optional]; + return this.nameForNamedType(unionType); + } + ); + } + + protected emitUsageHeader(): void { + // To be overridden + } + + protected emitHeader(): void { + if (this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + } else { + this.emitUsageHeader(); + } + + this.ensureBlankLine(); + this.emitLine("package ", this._kotlinOptions.packageName); + this.ensureBlankLine(); + } + + protected emitTopLevelPrimitive(t: PrimitiveType, name: Name): void { + const elementType = this.kotlinType(t); + this.emitLine(["typealias ", name, " = ", elementType, ""]); + } + + protected emitTopLevelArray(t: ArrayType, name: Name): void { + const elementType = this.kotlinType(t.items); + this.emitLine(["typealias ", name, " = ArrayList<", elementType, ">"]); + } + + protected emitTopLevelMap(t: MapType, name: Name): void { + const elementType = this.kotlinType(t.values); + this.emitLine(["typealias ", name, " = HashMap"]); + } + + protected emitEmptyClassDefinition(c: ClassType, className: Name): void { + this.emitDescription(this.descriptionForType(c)); + this.emitClassAnnotations(c, className); + this.emitLine("class ", className, "()"); + } + + protected emitClassDefinition(c: ClassType, className: Name): void { + if (c.getProperties().size === 0) { + this.emitEmptyClassDefinition(c, className); + return; + } + + const kotlinType = (p: ClassProperty): Sourcelike => { + if (p.isOptional) { + return [this.kotlinType(p.type, true, true), "?"]; + } else { + return this.kotlinType(p.type, true); + } + }; + + this.emitDescription(this.descriptionForType(c)); + this.emitClassAnnotations(c, className); + this.emitLine("data class ", className, " ("); + this.indent(() => { + let count = c.getProperties().size; + let first = true; + this.forEachClassProperty(c, "none", (name, jsonName, p) => { + const nullable = p.type.kind === "union" && nullableFromUnion(p.type as UnionType) !== null; + const nullableOrOptional = p.isOptional || p.type.kind === "null" || nullable; + const last = --count === 0; + let meta: Array<() => void> = []; + + const description = this.descriptionForClassProperty(c, jsonName); + if (description !== undefined) { + meta.push(() => this.emitDescription(description)); + } + + this.renameAttribute(name, jsonName, !nullableOrOptional, meta); + + if (meta.length > 0 && !first) { + this.ensureBlankLine(); + } + + for (const emit of meta) { + emit(); + } + + this.emitLine("val ", name, ": ", kotlinType(p), nullableOrOptional ? " = null" : "", last ? "" : ","); + + if (meta.length > 0 && !last) { + this.ensureBlankLine(); + } + + first = false; + }); + }); + + this.emitClassDefinitionMethods(c, className); + } + + protected emitClassDefinitionMethods(_c: ClassType, _className: Name): void { + this.emitLine(")"); + } + + protected emitClassAnnotations(_c: Type, _className: Name): void { + // to be overridden + } + + protected renameAttribute(_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>): void { + // to be overridden + } + + protected emitEnumDefinition(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + + this.emitBlock(["enum class ", enumName], () => { + let count = e.cases.size; + this.forEachEnumCase(e, "none", name => { + this.emitLine(name, --count === 0 ? "" : ","); + }); + }); + } + + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + function sortBy(t: Type): string { + const kind = t.kind; + if (kind === "class") return kind; + return "_" + kind; + } + + this.emitDescription(this.descriptionForType(u)); + + const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); + this.emitClassAnnotations(u, unionName); + this.emitBlock(["sealed class ", unionName], () => { + { + let table: Sourcelike[][] = []; + this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { + table.push([ + ["class ", name, "(val value: ", this.kotlinType(t), ")"], + [" : ", unionName, "()"] + ]); + }); + if (maybeNull !== null) { + table.push([ + ["class ", this.nameForUnionMember(u, maybeNull), "()"], + [" : ", unionName, "()"] + ]); + } + + this.emitTable(table); + } + + this.emitUnionDefinitionMethods(u, nonNulls, maybeNull, unionName); + }); + } + + protected emitUnionDefinitionMethods( + _u: UnionType, + _nonNulls: ReadonlySet, + _maybeNull: PrimitiveType | null, + _unionName: Name + ): void { + // to be overridden + } + + protected emitSourceStructure(): void { + this.emitHeader(); + + // Top-level arrays, maps + this.forEachTopLevel("leading", (t, name) => { + if (t instanceof ArrayType) { + this.emitTopLevelArray(t, name); + } else if (t instanceof MapType) { + this.emitTopLevelMap(t, name); + } else if (t.isPrimitive()) { + this.emitTopLevelPrimitive(t, name); + } + }); + + this.forEachNamedType( + "leading-and-interposing", + (c: ClassType, n: Name) => this.emitClassDefinition(c, n), + (e, n) => this.emitEnumDefinition(e, n), + (u, n) => this.emitUnionDefinition(u, n) + ); + } +} diff --git a/packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts b/packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts new file mode 100644 index 000000000..66a579b45 --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts @@ -0,0 +1,121 @@ +import { type Name } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { camelCase } from "../../support/Strings"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ArrayType, type EnumType, type MapType, type Type } from "../../Type"; + +import { KotlinRenderer } from "./KotlinRenderer"; +import { type kotlinOptions } from "./language"; +import { stringEscape } from "./utils"; + +/** + * Currently supports simple classes, enums, and TS string unions (which are also enums). + * TODO: Union, Any, Top Level Array, Top Level Map + */ +export class KotlinXRenderer extends KotlinRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + _kotlinOptions: OptionValues + ) { + super(targetLanguage, renderContext, _kotlinOptions); + } + + protected anySourceType(optional: string): Sourcelike { + return ["JsonElement", optional]; + } + + protected arrayType(arrayType: ArrayType, withIssues = false, noOptional = false): Sourcelike { + const valType = this.kotlinType(arrayType.items, withIssues, true); + const name = this.sourcelikeToString(valType); + if (name === "JsonObject" || name === "JsonElement") { + return "JsonArray"; + } + + return super.arrayType(arrayType, withIssues, noOptional); + } + + protected mapType(mapType: MapType, withIssues = false, noOptional = false): Sourcelike { + const valType = this.kotlinType(mapType.values, withIssues, true); + const name = this.sourcelikeToString(valType); + if (name === "JsonObject" || name === "JsonElement") { + return "JsonObject"; + } + + return super.mapType(mapType, withIssues, noOptional); + } + + protected emitTopLevelMap(t: MapType, name: Name): void { + const elementType = this.kotlinType(t.values); + if (elementType === "JsonObject") { + this.emitLine(["typealias ", name, " = JsonObject"]); + } else { + super.emitTopLevelMap(t, name); + } + } + + protected emitTopLevelArray(t: ArrayType, name: Name): void { + const elementType = this.kotlinType(t.items); + this.emitLine(["typealias ", name, " = JsonArray<", elementType, ">"]); + } + + protected emitUsageHeader(): void { + this.emitLine("// To parse the JSON, install kotlin's serialization plugin and do:"); + this.emitLine("//"); + const table: Sourcelike[][] = []; + table.push(["// val ", "json", " = Json { allowStructuredMapKeys = true }"]); + this.forEachTopLevel("none", (_, name) => { + table.push([ + "// val ", + modifySource(camelCase, name), + ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)` + ]); + }); + this.emitTable(table); + } + + protected emitHeader(): void { + super.emitHeader(); + + this.emitLine("import kotlinx.serialization.*"); + this.emitLine("import kotlinx.serialization.json.*"); + this.emitLine("import kotlinx.serialization.descriptors.*"); + this.emitLine("import kotlinx.serialization.encoding.*"); + } + + protected emitClassAnnotations(_c: Type, _className: Name): void { + this.emitLine("@Serializable"); + } + + protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): void { + const rename = this._rename(name, jsonName); + if (rename !== undefined) { + meta.push(() => this.emitLine(rename)); + } + } + + private _rename(propName: Name, jsonName: string): Sourcelike | undefined { + const escapedName = stringEscape(jsonName); + const namesDiffer = this.sourcelikeToString(propName) !== escapedName; + if (namesDiffer) { + return ['@SerialName("', escapedName, '")']; + } + + return undefined; + } + + protected emitEnumDefinition(e: EnumType, enumName: Name): void { + this.emitDescription(this.descriptionForType(e)); + + this.emitLine(["@Serializable"]); + this.emitBlock(["enum class ", enumName, "(val value: String)"], () => { + let count = e.cases.size; + this.forEachEnumCase(e, "none", (name, json) => { + const jsonEnum = stringEscape(json); + this.emitLine(`@SerialName("${jsonEnum}") `, name, `("${jsonEnum}")`, --count === 0 ? ";" : ","); + }); + }); + } +} diff --git a/packages/quicktype-core/src/language/Kotlin/constants.ts b/packages/quicktype-core/src/language/Kotlin/constants.ts new file mode 100644 index 000000000..8e83c7388 --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/constants.ts @@ -0,0 +1,51 @@ +export const keywords = [ + "package", + "as", + "typealias", + "class", + "this", + "super", + "val", + "var", + "fun", + "for", + "null", + "true", + "false", + "is", + "in", + "throw", + "return", + "break", + "continue", + "object", + "if", + "try", + "else", + "while", + "do", + "when", + "interface", + "typeof", + "klaxon", + "toJson", + "Any", + "Boolean", + "Double", + "Float", + "Long", + "Int", + "Short", + "System", + "Byte", + "String", + "Array", + "List", + "Map", + "Enum", + "Class", + "JsonObject", + "JsonValue", + "Converter", + "Klaxon" +] as const; diff --git a/packages/quicktype-core/src/language/Kotlin/index.ts b/packages/quicktype-core/src/language/Kotlin/index.ts new file mode 100644 index 000000000..e6459d694 --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/index.ts @@ -0,0 +1,5 @@ +export { KotlinTargetLanguage, kotlinOptions } from "./language"; +export { KotlinRenderer } from "./KotlinRenderer"; +export { KotlinJacksonRenderer } from "./KotlinJacksonRenderer"; +export { KotlinKlaxonRenderer } from "./KotlinKlaxonRenderer"; +export { KotlinXRenderer } from "./KotlinXRenderer"; diff --git a/packages/quicktype-core/src/language/Kotlin/language.ts b/packages/quicktype-core/src/language/Kotlin/language.ts new file mode 100644 index 000000000..59a150dc9 --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/language.ts @@ -0,0 +1,70 @@ +import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type RenderContext } from "../../Renderer"; +import { EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; +import { assertNever } from "../../support/Support"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { KotlinJacksonRenderer } from "./KotlinJacksonRenderer"; +import { KotlinKlaxonRenderer } from "./KotlinKlaxonRenderer"; +import { KotlinRenderer } from "./KotlinRenderer"; +import { KotlinXRenderer } from "./KotlinXRenderer"; + +export enum Framework { + None = "None", + Jackson = "Jackson", + Klaxon = "Klaxon", + KotlinX = "KotlinX" +} + +export const kotlinOptions = { + framework: new EnumOption( + "framework", + "Serialization framework", + [ + ["just-types", Framework.None], + ["jackson", Framework.Jackson], + ["klaxon", Framework.Klaxon], + ["kotlinx", Framework.KotlinX] + ], + "klaxon" + ), + acronymStyle: acronymOption(AcronymStyleOptions.Pascal), + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") +}; + +export class KotlinTargetLanguage extends TargetLanguage { + public constructor() { + super("Kotlin", ["kotlin"], "kt"); + } + + protected getOptions(): Array> { + return [kotlinOptions.framework, kotlinOptions.acronymStyle, kotlinOptions.packageName]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { + const options = getOptionValues(kotlinOptions, untypedOptionValues); + + switch (options.framework) { + case Framework.None: + return new KotlinRenderer(this, renderContext, options); + case Framework.Jackson: + return new KotlinJacksonRenderer(this, renderContext, options); + case Framework.Klaxon: + return new KotlinKlaxonRenderer(this, renderContext, options); + case Framework.KotlinX: + return new KotlinXRenderer(this, renderContext, options); + default: + return assertNever(options.framework); + } + } +} diff --git a/packages/quicktype-core/src/language/Kotlin/utils.ts b/packages/quicktype-core/src/language/Kotlin/utils.ts new file mode 100644 index 000000000..1668782ea --- /dev/null +++ b/packages/quicktype-core/src/language/Kotlin/utils.ts @@ -0,0 +1,54 @@ +import { + allLowerWordStyle, + allUpperWordStyle, + combineWords, + escapeNonPrintableMapper, + firstUpperWordStyle, + intToHex, + isDigit, + isLetterOrUnderscore, + isNumeric, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap +} from "../../support/Strings"; + +function isPartCharacter(codePoint: number): boolean { + return isLetterOrUnderscore(codePoint) || isNumeric(codePoint); +} + +function isStartCharacter(codePoint: number): boolean { + return isPartCharacter(codePoint) && !isDigit(codePoint); +} + +const legalizeName = legalizeCharacters(isPartCharacter); + +export function kotlinNameStyle( + isUpper: boolean, + original: string, + acronymsStyle: (s: string) => string = allUpperWordStyle +): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + isUpper ? firstUpperWordStyle : allLowerWordStyle, + firstUpperWordStyle, + isUpper ? allUpperWordStyle : allLowerWordStyle, + acronymsStyle, + "", + isStartCharacter + ); +} + +function unicodeEscape(codePoint: number): string { + return "\\u" + intToHex(codePoint, 4); +} + +const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); + +export function stringEscape(s: string): string { + // "$this" is a template string in Kotlin so we have to escape $ + return _stringEscape(s).replace(/\$/g, "\\$"); +} From 667c4f07d928beeb97e8a7aea2d0276e921911bf Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:11:37 -0700 Subject: [PATCH 52/80] move JSONSchema to own dir --- .../JSONSchemaRenderer.ts} | 68 ++----------------- .../src/language/JSONSchema/index.ts | 2 + .../src/language/JSONSchema/language.ts | 33 +++++++++ .../src/language/JSONSchema/utils.ts | 26 +++++++ 4 files changed, 68 insertions(+), 61 deletions(-) rename packages/quicktype-core/src/language/{JSONSchema.ts => JSONSchema/JSONSchemaRenderer.ts} (75%) create mode 100644 packages/quicktype-core/src/language/JSONSchema/index.ts create mode 100644 packages/quicktype-core/src/language/JSONSchema/language.ts create mode 100644 packages/quicktype-core/src/language/JSONSchema/utils.ts diff --git a/packages/quicktype-core/src/language/JSONSchema.ts b/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts similarity index 75% rename from packages/quicktype-core/src/language/JSONSchema.ts rename to packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts index 978906075..9b24306fa 100644 --- a/packages/quicktype-core/src/language/JSONSchema.ts +++ b/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts @@ -1,73 +1,19 @@ import { iterableFirst, mapFirst } from "collection-utils"; -import { addDescriptionToSchema } from "../attributes/Description"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { type Option } from "../RendererOptions"; -import { - allUpperWordStyle, - combineWords, - firstUpperWordStyle, - legalizeCharacters, - splitIntoWords -} from "../support/Strings"; -import { defined, panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; +import { addDescriptionToSchema } from "../../attributes/Description"; +import { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type Name, type Namer } from "../../Naming"; +import { defined, panic } from "../../support/Support"; import { type EnumType, type ObjectType, type Type, type UnionType, transformedStringTypeTargetTypeKindsMap -} from "../Type"; -import { type StringTypeMapping, getNoStringTypeMapping } from "../TypeBuilder"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchTypeExhaustive } from "../TypeUtils"; - -export class JSONSchemaTargetLanguage extends TargetLanguage { - public constructor() { - super("JSON Schema", ["schema", "json-schema"], "schema"); - } - - protected getOptions(): Array> { - return []; - } - - public get stringTypeMapping(): StringTypeMapping { - return getNoStringTypeMapping(); - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsFullObjectType(): boolean { - return true; - } +} from "../../Type"; +import { matchTypeExhaustive } from "../../TypeUtils"; - protected makeRenderer(renderContext: RenderContext, _untypedOptionValues: FixMeOptionsType): JSONSchemaRenderer { - return new JSONSchemaRenderer(this, renderContext); - } -} - -const namingFunction = funPrefixNamer("namer", jsonNameStyle); - -const legalizeName = legalizeCharacters(cp => cp >= 32 && cp < 128 && cp !== 0x2f /* slash */); - -function jsonNameStyle(original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - firstUpperWordStyle, - firstUpperWordStyle, - allUpperWordStyle, - allUpperWordStyle, - "", - _ => true - ); -} +import { namingFunction } from "./utils"; interface Schema { // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/quicktype-core/src/language/JSONSchema/index.ts b/packages/quicktype-core/src/language/JSONSchema/index.ts new file mode 100644 index 000000000..6cb0b7958 --- /dev/null +++ b/packages/quicktype-core/src/language/JSONSchema/index.ts @@ -0,0 +1,2 @@ +export { JSONSchemaTargetLanguage } from "./language"; +export { JSONSchemaRenderer } from "./JSONSchemaRenderer"; diff --git a/packages/quicktype-core/src/language/JSONSchema/language.ts b/packages/quicktype-core/src/language/JSONSchema/language.ts new file mode 100644 index 000000000..7ada4a1e0 --- /dev/null +++ b/packages/quicktype-core/src/language/JSONSchema/language.ts @@ -0,0 +1,33 @@ +import { type RenderContext } from "../../Renderer"; +import { type Option } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type StringTypeMapping, getNoStringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType } from "../../types"; + +import { JSONSchemaRenderer } from "./JSONSchemaRenderer"; + +export class JSONSchemaTargetLanguage extends TargetLanguage { + public constructor() { + super("JSON Schema", ["schema", "json-schema"], "schema"); + } + + protected getOptions(): Array> { + return []; + } + + public get stringTypeMapping(): StringTypeMapping { + return getNoStringTypeMapping(); + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsFullObjectType(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, _untypedOptionValues: FixMeOptionsType): JSONSchemaRenderer { + return new JSONSchemaRenderer(this, renderContext); + } +} diff --git a/packages/quicktype-core/src/language/JSONSchema/utils.ts b/packages/quicktype-core/src/language/JSONSchema/utils.ts new file mode 100644 index 000000000..0c66ee4f6 --- /dev/null +++ b/packages/quicktype-core/src/language/JSONSchema/utils.ts @@ -0,0 +1,26 @@ +import { funPrefixNamer } from "../../Naming"; +import { + legalizeCharacters, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allUpperWordStyle +} from "../../support/Strings"; + +export const namingFunction = funPrefixNamer("namer", jsonNameStyle); + +const legalizeName = legalizeCharacters(cp => cp >= 32 && cp < 128 && cp !== 0x2f /* slash */); + +function jsonNameStyle(original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + firstUpperWordStyle, + firstUpperWordStyle, + allUpperWordStyle, + allUpperWordStyle, + "", + _ => true + ); +} From 3be73acb0ca25cbac669667d46b1227dbf0ec383 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:17:06 -0700 Subject: [PATCH 53/80] move JavaScript to own dir, add unicodeMaps --- .../JavaScriptRenderer.ts} | 100 +++--------------- .../src/language/JavaScript/index.ts | 0 .../src/language/JavaScript/language.ts | 68 ++++++++++++ .../unicodeMaps.ts} | 0 .../src/language/JavaScript/utils.ts | 5 + 5 files changed, 89 insertions(+), 84 deletions(-) rename packages/quicktype-core/src/language/{JavaScript.ts => JavaScript/JavaScriptRenderer.ts} (84%) create mode 100644 packages/quicktype-core/src/language/JavaScript/index.ts create mode 100644 packages/quicktype-core/src/language/JavaScript/language.ts rename packages/quicktype-core/src/language/{JavaScriptUnicodeMaps.ts => JavaScript/unicodeMaps.ts} (100%) create mode 100644 packages/quicktype-core/src/language/JavaScript/utils.ts diff --git a/packages/quicktype-core/src/language/JavaScript.ts b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts similarity index 84% rename from packages/quicktype-core/src/language/JavaScript.ts rename to packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts index 440502cff..7dfa79b33 100644 --- a/packages/quicktype-core/src/language/JavaScript.ts +++ b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts @@ -1,12 +1,12 @@ import { arrayIntercalate } from "collection-utils"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, modifySource } from "../Source"; -import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; -import { ConvertersOptions, convertersOption } from "../support/Converters"; +import { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { acronymStyle } from "../../support/Acronyms"; +import { ConvertersOptions } from "../../support/Converters"; import { allLowerWordStyle, camelCase, @@ -14,46 +14,16 @@ import { combineWords, firstUpperWordStyle, splitIntoWords, - utf16LegalizeCharacters, utf16StringEscape -} from "../support/Strings"; -import { panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { - type ClassProperty, - type ClassType, - type ObjectType, - type PrimitiveStringTypeKind, - type TransformedStringTypeKind, - type Type -} from "../Type"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { directlyReachableSingleNamedType, matchType } from "../TypeUtils"; - -import { isES3IdentifierPart, isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; - -export const javaScriptOptions = { - acronymStyle: acronymOption(AcronymStyleOptions.Pascal), - runtimeTypecheck: new BooleanOption("runtime-typecheck", "Verify JSON.parse results at runtime", true), - runtimeTypecheckIgnoreUnknownProperties: new BooleanOption( - "runtime-typecheck-ignore-unknown-properties", - "Ignore unknown properties when verifying at runtime", - false, - "secondary" - ), - converters: convertersOption(), - rawType: new EnumOption<"json" | "any">( - "raw-type", - "Type of raw input (json by default)", - [ - ["json", "json"], - ["any", "any"] - ], - "json", - "secondary" - ) -}; +} from "../../support/Strings"; +import { panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassProperty, type ClassType, type ObjectType, type Type } from "../../Type"; +import { directlyReachableSingleNamedType, matchType } from "../../TypeUtils"; + +import { type javaScriptOptions } from "./language"; +import { isES3IdentifierStart } from "./unicodeMaps"; +import { legalizeName } from "./utils"; export interface JavaScriptTypeAnnotations { any: string; @@ -65,44 +35,6 @@ export interface JavaScriptTypeAnnotations { stringArray: string; } -export class JavaScriptTargetLanguage extends TargetLanguage { - public constructor(displayName = "JavaScript", names: string[] = ["javascript", "js", "jsx"], extension = "js") { - super(displayName, names, extension); - } - - protected getOptions(): Array> { - return [ - javaScriptOptions.runtimeTypecheck, - javaScriptOptions.runtimeTypecheckIgnoreUnknownProperties, - javaScriptOptions.acronymStyle, - javaScriptOptions.converters, - javaScriptOptions.rawType - ]; - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - const dateTimeType = "date-time"; - mapping.set("date", dateTimeType); - mapping.set("date-time", dateTimeType); - return mapping; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsFullObjectType(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): JavaScriptRenderer { - return new JavaScriptRenderer(this, renderContext, getOptionValues(javaScriptOptions, untypedOptionValues)); - } -} - -export const legalizeName = utf16LegalizeCharacters(isES3IdentifierPart); - const identityNamingFunction = funPrefixNamer("properties", s => s); export class JavaScriptRenderer extends ConvenienceRenderer { diff --git a/packages/quicktype-core/src/language/JavaScript/index.ts b/packages/quicktype-core/src/language/JavaScript/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/quicktype-core/src/language/JavaScript/language.ts b/packages/quicktype-core/src/language/JavaScript/language.ts new file mode 100644 index 000000000..85d61bbb6 --- /dev/null +++ b/packages/quicktype-core/src/language/JavaScript/language.ts @@ -0,0 +1,68 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, getOptionValues } from "../../RendererOptions"; +import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; +import { convertersOption } from "../../support/Converters"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { JavaScriptRenderer } from "./JavaScriptRenderer"; + +export const javaScriptOptions = { + acronymStyle: acronymOption(AcronymStyleOptions.Pascal), + runtimeTypecheck: new BooleanOption("runtime-typecheck", "Verify JSON.parse results at runtime", true), + runtimeTypecheckIgnoreUnknownProperties: new BooleanOption( + "runtime-typecheck-ignore-unknown-properties", + "Ignore unknown properties when verifying at runtime", + false, + "secondary" + ), + converters: convertersOption(), + rawType: new EnumOption<"json" | "any">( + "raw-type", + "Type of raw input (json by default)", + [ + ["json", "json"], + ["any", "any"] + ], + "json", + "secondary" + ) +}; + +export class JavaScriptTargetLanguage extends TargetLanguage { + public constructor(displayName = "JavaScript", names: string[] = ["javascript", "js", "jsx"], extension = "js") { + super(displayName, names, extension); + } + + protected getOptions(): Array> { + return [ + javaScriptOptions.runtimeTypecheck, + javaScriptOptions.runtimeTypecheckIgnoreUnknownProperties, + javaScriptOptions.acronymStyle, + javaScriptOptions.converters, + javaScriptOptions.rawType + ]; + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + const dateTimeType = "date-time"; + mapping.set("date", dateTimeType); + mapping.set("date-time", dateTimeType); + return mapping; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsFullObjectType(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): JavaScriptRenderer { + return new JavaScriptRenderer(this, renderContext, getOptionValues(javaScriptOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts b/packages/quicktype-core/src/language/JavaScript/unicodeMaps.ts similarity index 100% rename from packages/quicktype-core/src/language/JavaScriptUnicodeMaps.ts rename to packages/quicktype-core/src/language/JavaScript/unicodeMaps.ts diff --git a/packages/quicktype-core/src/language/JavaScript/utils.ts b/packages/quicktype-core/src/language/JavaScript/utils.ts new file mode 100644 index 000000000..7acc4c931 --- /dev/null +++ b/packages/quicktype-core/src/language/JavaScript/utils.ts @@ -0,0 +1,5 @@ +import { utf16LegalizeCharacters } from "../../support/Strings"; + +import { isES3IdentifierPart } from "./unicodeMaps"; + +export const legalizeName = utf16LegalizeCharacters(isES3IdentifierPart); From 5d4fbcea4ad7ec77e0f839cfef05d106bf8ec9c6 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:17:43 -0700 Subject: [PATCH 54/80] move JavaScriptPropTypes to own dir --- .../JavaScriptPropTypesRenderer.ts} | 70 ++++--------------- .../src/language/JavaScriptPropTypes/index.ts | 0 .../language/JavaScriptPropTypes/language.ts | 47 +++++++++++++ 3 files changed, 62 insertions(+), 55 deletions(-) rename packages/quicktype-core/src/language/{JavaScriptPropTypes.ts => JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts} (80%) create mode 100644 packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts create mode 100644 packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts similarity index 80% rename from packages/quicktype-core/src/language/JavaScriptPropTypes.ts rename to packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts index 6754e83e2..4dcd6ee91 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts @@ -1,13 +1,11 @@ -import { panic } from "@glideapps/ts-necessities"; import { arrayIntercalate } from "collection-utils"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { EnumOption, type Option, type OptionValues, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; -import { AcronymStyleOptions, acronymOption, acronymStyle } from "../support/Acronyms"; -import { convertersOption } from "../support/Converters"; +import { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike } from "../../Source"; +import { acronymStyle } from "../../support/Acronyms"; import { allLowerWordStyle, capitalize, @@ -15,53 +13,15 @@ import { firstUpperWordStyle, splitIntoWords, utf16StringEscape -} from "../support/Strings"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ArrayType, type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { directlyReachableSingleNamedType, matchType } from "../TypeUtils"; - -import { legalizeName } from "./JavaScript"; -import { isES3IdentifierStart } from "./JavaScriptUnicodeMaps"; - -export const javaScriptPropTypesOptions = { - acronymStyle: acronymOption(AcronymStyleOptions.Pascal), - converters: convertersOption(), - moduleSystem: new EnumOption( - "module-system", - "Which module system to use", - [ - ["common-js", false], - ["es6", true] - ], - "es6" - ) -}; - -export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { - protected getOptions(): Array> { - return [javaScriptPropTypesOptions.acronymStyle, javaScriptPropTypesOptions.converters]; - } - - public constructor( - displayName = "JavaScript PropTypes", - names: string[] = ["javascript-prop-types"], - extension = "js" - ) { - super(displayName, names, extension); - } - - protected makeRenderer( - renderContext: RenderContext, - untypedOptionValues: FixMeOptionsType - ): JavaScriptPropTypesRenderer { - return new JavaScriptPropTypesRenderer( - this, - renderContext, - getOptionValues(javaScriptPropTypesOptions, untypedOptionValues) - ); - } -} +} from "../../support/Strings"; +import { panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type } from "../../Type"; +import { directlyReachableSingleNamedType, matchType } from "../../TypeUtils"; +import { isES3IdentifierStart } from "../JavaScript/unicodeMaps"; +import { legalizeName } from "../JavaScript/utils"; + +import { type javaScriptPropTypesOptions } from "./language"; const identityNamingFunction = funPrefixNamer("properties", s => s); diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts new file mode 100644 index 000000000..8ba620927 --- /dev/null +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts @@ -0,0 +1,47 @@ +import { type RenderContext } from "../../Renderer"; +import { EnumOption, type Option, getOptionValues } from "../../RendererOptions"; +import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; +import { convertersOption } from "../../support/Converters"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { JavaScriptPropTypesRenderer } from "./JavaScriptPropTypesRenderer"; + +export const javaScriptPropTypesOptions = { + acronymStyle: acronymOption(AcronymStyleOptions.Pascal), + converters: convertersOption(), + moduleSystem: new EnumOption( + "module-system", + "Which module system to use", + [ + ["common-js", false], + ["es6", true] + ], + "es6" + ) +}; + +export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { + protected getOptions(): Array> { + return [javaScriptPropTypesOptions.acronymStyle, javaScriptPropTypesOptions.converters]; + } + + public constructor( + displayName = "JavaScript PropTypes", + names: string[] = ["javascript-prop-types"], + extension = "js" + ) { + super(displayName, names, extension); + } + + protected makeRenderer( + renderContext: RenderContext, + untypedOptionValues: FixMeOptionsType + ): JavaScriptPropTypesRenderer { + return new JavaScriptPropTypesRenderer( + this, + renderContext, + getOptionValues(javaScriptPropTypesOptions, untypedOptionValues) + ); + } +} From 097ea3252f5a632436d1cff1a3cc645503228804 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:24:25 -0700 Subject: [PATCH 55/80] move Java to own dir --- .../src/language/Java/DateTimeProvider.ts | 261 ++++++++ .../src/language/Java/JavaJacksonRenderer.ts | 567 ++++++++++++++++++ .../src/language/Java/JavaRenderer.ts | 514 ++++++++++++++++ .../src/language/Java/constants.ts | 69 +++ .../quicktype-core/src/language/Java/index.ts | 3 + .../src/language/Java/language.ts | 77 +++ .../quicktype-core/src/language/Java/utils.ts | 46 ++ 7 files changed, 1537 insertions(+) create mode 100644 packages/quicktype-core/src/language/Java/DateTimeProvider.ts create mode 100644 packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts create mode 100644 packages/quicktype-core/src/language/Java/JavaRenderer.ts create mode 100644 packages/quicktype-core/src/language/Java/constants.ts create mode 100644 packages/quicktype-core/src/language/Java/index.ts create mode 100644 packages/quicktype-core/src/language/Java/language.ts create mode 100644 packages/quicktype-core/src/language/Java/utils.ts diff --git a/packages/quicktype-core/src/language/Java/DateTimeProvider.ts b/packages/quicktype-core/src/language/Java/DateTimeProvider.ts new file mode 100644 index 000000000..78228db01 --- /dev/null +++ b/packages/quicktype-core/src/language/Java/DateTimeProvider.ts @@ -0,0 +1,261 @@ +import { type Sourcelike } from "../../Source"; + +import { type JavaRenderer } from "./JavaRenderer"; + +export abstract class JavaDateTimeProvider { + public constructor( + protected readonly _renderer: JavaRenderer, + protected readonly _className: string + ) {} + + public abstract keywords: string[]; + + public abstract dateTimeImports: string[]; + + public abstract dateImports: string[]; + + public abstract timeImports: string[]; + + public abstract converterImports: string[]; + + public abstract dateTimeType: string; + + public abstract dateType: string; + + public abstract timeType: string; + + public abstract dateTimeJacksonAnnotations: string[]; + + public abstract dateJacksonAnnotations: string[]; + + public abstract timeJacksonAnnotations: string[]; + + public abstract emitDateTimeConverters(): void; + + public shouldEmitDateTimeConverter = true; + + public shouldEmitTimeConverter = true; + + public shouldEmitDateConverter = true; + + public abstract convertStringToDateTime(variable: Sourcelike): Sourcelike; + public abstract convertStringToTime(variable: Sourcelike): Sourcelike; + public abstract convertStringToDate(variable: Sourcelike): Sourcelike; + + public abstract convertDateTimeToString(variable: Sourcelike): Sourcelike; + public abstract convertTimeToString(variable: Sourcelike): Sourcelike; + public abstract convertDateToString(variable: Sourcelike): Sourcelike; +} + +export class Java8DateTimeProvider extends JavaDateTimeProvider { + public keywords = [ + "LocalDate", + "OffsetDateTime", + "OffsetTime", + "ZoneOffset", + "ZonedDateTime", + "DateTimeFormatter", + "DateTimeFormatterBuilder", + "ChronoField" + ]; + + public dateTimeImports: string[] = ["java.time.OffsetDateTime"]; + + public dateImports: string[] = ["java.time.LocalDate"]; + + public timeImports: string[] = ["java.time.OffsetTime"]; + + public converterImports: string[] = [ + "java.time.LocalDate", + "java.time.OffsetDateTime", + "java.time.OffsetTime", + "java.time.ZoneOffset", + "java.time.ZonedDateTime", + "java.time.format.DateTimeFormatter", + "java.time.format.DateTimeFormatterBuilder", + "java.time.temporal.ChronoField" + ]; + + public dateTimeType = "OffsetDateTime"; + + public dateType = "LocalDate"; + + public timeType = "OffsetTime"; + + public dateTimeJacksonAnnotations: string[] = []; + + public dateJacksonAnnotations: string[] = []; + + public timeJacksonAnnotations: string[] = []; + + public emitDateTimeConverters(): void { + this._renderer.ensureBlankLine(); + this._renderer.emitLine( + "private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()" + ); + this._renderer.indent(() => + this._renderer.indent(() => { + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_DATE_TIME)"); + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)"); + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_INSTANT)"); + this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SX"))'); + this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX"))'); + this._renderer.emitLine('.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))'); + this._renderer.emitLine(".toFormatter()"); + this._renderer.emitLine(".withZone(ZoneOffset.UTC);"); + }) + ); + this._renderer.ensureBlankLine(); + this._renderer.emitBlock("public static OffsetDateTime parseDateTimeString(String str)", () => { + this._renderer.emitLine( + "return ZonedDateTime.from(Converter.DATE_TIME_FORMATTER.parse(str)).toOffsetDateTime();" + ); + }); + + this._renderer.ensureBlankLine(); + this._renderer.emitLine( + "private static final DateTimeFormatter TIME_FORMATTER = new DateTimeFormatterBuilder()" + ); + this._renderer.indent(() => + this._renderer.indent(() => { + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_TIME)"); + this._renderer.emitLine(".appendOptional(DateTimeFormatter.ISO_OFFSET_TIME)"); + this._renderer.emitLine(".parseDefaulting(ChronoField.YEAR, 2020)"); + this._renderer.emitLine(".parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)"); + this._renderer.emitLine(".parseDefaulting(ChronoField.DAY_OF_MONTH, 1)"); + this._renderer.emitLine(".toFormatter()"); + this._renderer.emitLine(".withZone(ZoneOffset.UTC);"); + }) + ); + this._renderer.ensureBlankLine(); + this._renderer.emitBlock("public static OffsetTime parseTimeString(String str)", () => { + this._renderer.emitLine( + "return ZonedDateTime.from(Converter.TIME_FORMATTER.parse(str)).toOffsetDateTime().toOffsetTime();" + ); + }); + } + + public convertStringToDateTime(variable: Sourcelike): Sourcelike { + return [this._className, ".parseDateTimeString(", variable, ")"]; + } + + public convertStringToTime(variable: Sourcelike): Sourcelike { + return [this._className, ".parseTimeString(", variable, ")"]; + } + + public convertStringToDate(variable: Sourcelike): Sourcelike { + return ["LocalDate.parse(", variable, ")"]; + } + + public convertDateTimeToString(variable: Sourcelike): Sourcelike { + return [variable, ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)"]; + } + + public convertTimeToString(variable: Sourcelike): Sourcelike { + return [variable, ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_TIME)"]; + } + + public convertDateToString(variable: Sourcelike): Sourcelike { + return [variable, ".format(java.time.format.DateTimeFormatter.ISO_DATE)"]; + } +} +export class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { + public keywords = ["SimpleDateFormat", "Date"]; + + public dateTimeImports: string[] = ["java.util.Date"]; + + public dateImports: string[] = ["java.util.Date"]; + + public timeImports: string[] = ["java.util.Date"]; + + public converterImports: string[] = ["java.util.Date", "java.text.SimpleDateFormat"]; + + public dateTimeType = "Date"; + + public dateType = "Date"; + + public timeType = "Date"; + + public dateTimeJacksonAnnotations: string[] = [ + '@JsonFormat(pattern = "yyyy-MM-dd\'T\'HH:mm:ssX", timezone = "UTC")' + ]; + + public dateJacksonAnnotations: string[] = ['@JsonFormat(pattern = "yyyy-MM-dd")']; + + public timeJacksonAnnotations: string[] = ['@JsonFormat(pattern = "HH:mm:ssX", timezone = "UTC")']; + + public shouldEmitTimeConverter = false; + + public shouldEmitDateConverter = false; + + public emitDateTimeConverters(): void { + this._renderer.ensureBlankLine(); + this._renderer.emitLine("private static final String[] DATE_TIME_FORMATS = {"); + this._renderer.indent(() => + this._renderer.indent(() => { + this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ss.SX\","); + this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ss.S\","); + this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ssX\","); + this._renderer.emitLine("\"yyyy-MM-dd'T'HH:mm:ss\","); + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss.SX",'); + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss.S",'); + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ssX",'); + this._renderer.emitLine('"yyyy-MM-dd HH:mm:ss",'); + this._renderer.emitLine('"HH:mm:ss.SZ",'); + this._renderer.emitLine('"HH:mm:ss.S",'); + this._renderer.emitLine('"HH:mm:ssZ",'); + this._renderer.emitLine('"HH:mm:ss",'); + this._renderer.emitLine('"yyyy-MM-dd",'); + }) + ); + this._renderer.emitLine("};"); + this._renderer.ensureBlankLine(); + this._renderer.emitBlock("public static Date parseAllDateTimeString(String str)", () => { + this._renderer.emitBlock("for (String format : DATE_TIME_FORMATS)", () => { + this._renderer.emitIgnoredTryCatchBlock(() => { + this._renderer.emitLine("return new SimpleDateFormat(format).parse(str);"); + }); + }); + this._renderer.emitLine("return null;"); + }); + + this._renderer.ensureBlankLine(); + this._renderer.emitBlock("public static String serializeDateTime(Date datetime)", () => { + this._renderer.emitLine("return new SimpleDateFormat(\"yyyy-MM-dd'T'hh:mm:ssZ\").format(datetime);"); + }); + + this._renderer.ensureBlankLine(); + this._renderer.emitBlock("public static String serializeDate(Date datetime)", () => { + this._renderer.emitLine('return new SimpleDateFormat("yyyy-MM-dd").format(datetime);'); + }); + + this._renderer.ensureBlankLine(); + this._renderer.emitBlock("public static String serializeTime(Date datetime)", () => { + this._renderer.emitLine('return new SimpleDateFormat("hh:mm:ssZ").format(datetime);'); + }); + } + + public convertStringToDateTime(variable: Sourcelike): Sourcelike { + return [this._className, ".parseAllDateTimeString(", variable, ")"]; + } + + public convertStringToTime(variable: Sourcelike): Sourcelike { + return [this._className, ".parseAllDateTimeString(", variable, ")"]; + } + + public convertStringToDate(variable: Sourcelike): Sourcelike { + return [this._className, ".parseAllDateTimeString(", variable, ")"]; + } + + public convertDateTimeToString(variable: Sourcelike): Sourcelike { + return [this._className, ".serializeDateTime(", variable, ")"]; + } + + public convertTimeToString(variable: Sourcelike): Sourcelike { + return [this._className, ".serializeTime(", variable, ")"]; + } + + public convertDateToString(variable: Sourcelike): Sourcelike { + return [this._className, ".serializeDate(", variable, ")"]; + } +} diff --git a/packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts b/packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts new file mode 100644 index 000000000..3329b61cd --- /dev/null +++ b/packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts @@ -0,0 +1,567 @@ +import { type Name } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike } from "../../Source"; +import { assertNever, panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, type ClassProperty, ClassType, EnumType, type Type, type TypeKind, UnionType } from "../../Type"; +import { removeNullFromUnion } from "../../TypeUtils"; + +import { JavaRenderer } from "./JavaRenderer"; +import { type javaOptions } from "./language"; +import { stringEscape } from "./utils"; + + +export class JacksonRenderer extends JavaRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + options: OptionValues + ) { + super(targetLanguage, renderContext, options); + } + + protected readonly _converterKeywords: string[] = [ + "JsonProperty", + "JsonDeserialize", + "JsonDeserializer", + "JsonSerialize", + "JsonSerializer", + "JsonParser", + "JsonProcessingException", + "DeserializationContext", + "SerializerProvider" + ]; + + protected emitClassAttributes(c: ClassType, _className: Name): void { + if (c.getProperties().size === 0) + this.emitLine("@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.NONE)"); + + super.emitClassAttributes(c, _className); + } + + protected annotationsForAccessor( + _c: ClassType, + _className: Name, + _propertyName: Name, + jsonName: string, + p: ClassProperty, + _isSetter: boolean + ): string[] { + const superAnnotations = super.annotationsForAccessor(_c, _className, _propertyName, jsonName, p, _isSetter); + + const annotations: string[] = ['@JsonProperty("' + stringEscape(jsonName) + '")']; + + switch (p.type.kind) { + case "date-time": + this._dateTimeProvider.dateTimeJacksonAnnotations.forEach(annotation => annotations.push(annotation)); + break; + case "date": + this._dateTimeProvider.dateJacksonAnnotations.forEach(annotation => annotations.push(annotation)); + break; + case "time": + this._dateTimeProvider.timeJacksonAnnotations.forEach(annotation => annotations.push(annotation)); + break; + default: + break; + } + + return [...superAnnotations, ...annotations]; + } + + protected importsForType(t: ClassType | UnionType | EnumType): string[] { + if (t instanceof ClassType) { + const imports = super.importsForType(t); + imports.push("com.fasterxml.jackson.annotation.*"); + return imports; + } + + if (t instanceof UnionType) { + const imports = super.importsForType(t); + imports.push( + "java.io.IOException", + "com.fasterxml.jackson.core.*", + "com.fasterxml.jackson.databind.*", + "com.fasterxml.jackson.databind.annotation.*" + ); + if (this._options.useList) { + imports.push("com.fasterxml.jackson.core.type.*"); + } + + return imports; + } + + if (t instanceof EnumType) { + const imports = super.importsForType(t); + imports.push("com.fasterxml.jackson.annotation.*"); + return imports; + } + + return assertNever(t); + } + + protected emitUnionAttributes(_u: UnionType, unionName: Name): void { + this.emitLine("@JsonDeserialize(using = ", unionName, ".Deserializer.class)"); + this.emitLine("@JsonSerialize(using = ", unionName, ".Serializer.class)"); + } + + protected emitUnionSerializer(u: UnionType, unionName: Name): void { + const stringBasedObjects: TypeKind[] = ["uuid", "time", "date", "date-time"]; + + const tokenCase = (tokenType: string): void => { + this.emitLine("case ", tokenType, ":"); + }; + + const emitNullDeserializer = (): void => { + this.indent(() => { + tokenCase("VALUE_NULL"); + this.indent(() => this.emitLine("break;")); + }); + }; + + const emitDeserializerCodeForStringObjects = ( + fieldName: Sourcelike, + kind: TypeKind, + parseFrom: string + ): void => { + switch (kind) { + case "date": + this.emitLine( + "value.", + fieldName, + " = ", + this._dateTimeProvider.convertStringToDate(parseFrom), + ";" + ); + + break; + case "time": + this.emitLine( + "value.", + fieldName, + " = ", + this._dateTimeProvider.convertStringToTime(parseFrom), + ";" + ); + + break; + case "date-time": + this.emitLine( + "value.", + fieldName, + " = ", + this._dateTimeProvider.convertStringToDateTime(parseFrom), + ";" + ); + break; + case "uuid": + this.emitLine("value.", fieldName, " = UUID.fromString(", parseFrom, ");"); + + break; + default: + return panic("Requested type isnt an object!"); + } + }; + + const emitDeserializeType = (t: Type, variableFieldName = ""): void => { + const { fieldName } = this.unionField(u, t); + const rendered = this.javaTypeWithoutGenerics(true, t); + if (this._options.useList && t instanceof ArrayType) { + this.emitLine( + "value.", + fieldName, + " = jsonParser.readValueAs(new TypeReference<", + rendered, + ">() {});" + ); + } else if (stringBasedObjects.some(stringBasedTypeKind => t.kind === stringBasedTypeKind)) { + emitDeserializerCodeForStringObjects(fieldName, t.kind, variableFieldName); + } else if (t.kind === "string") { + this.emitLine("value.", fieldName, " = ", variableFieldName, ";"); + } else if (t.kind === "enum") { + const { fieldType } = this.unionField(u, t, true); + this.emitLine("value.", fieldName, " = ", fieldType, ".forValue(", variableFieldName, ");"); + } else { + this.emitLine("value.", fieldName, " = jsonParser.readValueAs(", rendered, ".class);"); + } + }; + + const emitDeserializer = (tokenTypes: string[], kind: TypeKind): void => { + const t = u.findMember(kind); + if (t === undefined) return; + + this.indent(() => { + for (const tokenType of tokenTypes) { + tokenCase(tokenType); + } + + this.indent(() => { + emitDeserializeType(t); + this.emitLine("break;"); + }); + }); + }; + + const emitStringDeserializer = (): void => { + const enumType = u.findMember("enum"); + const stringType = u.findMember("string"); + + if ( + stringBasedObjects.every(kind => u.findMember(kind) === undefined) && + stringType === undefined && + enumType === undefined + ) + return; + + this.indent(() => { + tokenCase("VALUE_STRING"); + + this.indent(() => { + const fromVariable = "string"; + this.emitLine("String " + fromVariable + " = jsonParser.readValueAs(String.class);"); + + stringBasedObjects.forEach(kind => { + const type = u.findMember(kind); + if (type !== undefined) { + this.emitIgnoredTryCatchBlock(() => { + emitDeserializeType(type, fromVariable); + }); + } + }); + + if (enumType !== undefined) { + this.emitIgnoredTryCatchBlock(() => { + emitDeserializeType(enumType, fromVariable); + }); + } + + // String should be the last one if exists, because it cannot fail, unlike the parsers. + if (stringType !== undefined) { + emitDeserializeType(stringType, fromVariable); + } + + this.emitLine("break;"); + }); + }); + }; + + const emitNumberDeserializer = (): void => { + const integerType = u.findMember("integer"); + const doubleType = u.findMember("double"); + if (doubleType === undefined && integerType === undefined) return; + + this.indent(() => { + tokenCase("VALUE_NUMBER_INT"); + if (integerType !== undefined) { + this.indent(() => { + emitDeserializeType(integerType); + this.emitLine("break;"); + }); + } + + if (doubleType !== undefined) { + tokenCase("VALUE_NUMBER_FLOAT"); + this.indent(() => { + emitDeserializeType(doubleType); + this.emitLine("break;"); + }); + } + }); + }; + + const customObjectSerializer: TypeKind[] = ["time", "date", "date-time"]; + + const serializerCodeForType = (type: Type, fieldName: Sourcelike): Sourcelike => { + switch (type.kind) { + case "date": + return this._dateTimeProvider.convertDateToString(fieldName); + case "time": + return this._dateTimeProvider.convertTimeToString(fieldName); + case "date-time": + return this._dateTimeProvider.convertDateTimeToString(fieldName); + default: + return panic("Requested type doesn't have custom serializer code!"); + } + }; + + const emitSerializeType = (t: Type): void => { + let { fieldName } = this.unionField(u, t, true); + + this.emitBlock(["if (obj.", fieldName, " != null)"], () => { + if (customObjectSerializer.some(customSerializerType => t.kind === customSerializerType)) { + this.emitLine("jsonGenerator.writeObject(", serializerCodeForType(t, ["obj.", fieldName]), ");"); + } else { + this.emitLine("jsonGenerator.writeObject(obj.", fieldName, ");"); + } + + this.emitLine("return;"); + }); + }; + + const [maybeNull, nonNulls] = removeNullFromUnion(u); + + this.ensureBlankLine(); + this.emitBlock(["static class Deserializer extends JsonDeserializer<", unionName, ">"], () => { + this.emitLine("@Override"); + this.emitBlock( + [ + "public ", + unionName, + " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException" + ], + () => { + this.emitLine(unionName, " value = new ", unionName, "();"); + this.emitLine("switch (jsonParser.currentToken()) {"); + if (maybeNull !== null) emitNullDeserializer(); + emitNumberDeserializer(); + emitDeserializer(["VALUE_TRUE", "VALUE_FALSE"], "bool"); + emitStringDeserializer(); + emitDeserializer(["START_ARRAY"], "array"); + emitDeserializer(["START_OBJECT"], "class"); + emitDeserializer(["START_OBJECT"], "map"); + this.indent(() => + this.emitLine('default: throw new IOException("Cannot deserialize ', unionName, '");') + ); + this.emitLine("}"); + this.emitLine("return value;"); + } + ); + }); + this.ensureBlankLine(); + this.emitBlock(["static class Serializer extends JsonSerializer<", unionName, ">"], () => { + this.emitLine("@Override"); + this.emitBlock( + [ + "public void serialize(", + unionName, + " obj, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException" + ], + () => { + for (const t of nonNulls) { + emitSerializeType(t); + } + + if (maybeNull !== null) { + this.emitLine("jsonGenerator.writeNull();"); + } else { + this.emitLine('throw new IOException("', unionName, ' must not be null");'); + } + } + ); + }); + } + + protected emitEnumSerializationAttributes(_e: EnumType): void { + this.emitLine("@JsonValue"); + } + + protected emitEnumDeserializationAttributes(_e: EnumType): void { + this.emitLine("@JsonCreator"); + } + + protected emitOffsetDateTimeConverterModule(): void { + this.emitLine("SimpleModule module = new SimpleModule();"); + + if (this._dateTimeProvider.shouldEmitDateTimeConverter) { + this.emitLine( + "module.addDeserializer(", + this._dateTimeProvider.dateTimeType, + ".class, new JsonDeserializer<", + this._dateTimeProvider.dateTimeType, + ">() {" + ); + this.indent(() => { + this.emitLine("@Override"); + this.emitBlock( + [ + "public ", + this._dateTimeProvider.dateTimeType, + " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", + "throws IOException, JsonProcessingException" + ], + () => { + this.emitLine("String value = jsonParser.getText();"); + this.emitLine("return ", this._dateTimeProvider.convertStringToDateTime("value"), ";"); + } + ); + }); + this.emitLine("});"); + } + + if (!this._dateTimeProvider.shouldEmitTimeConverter) { + this.emitLine( + "module.addDeserializer(", + this._dateTimeProvider.timeType, + ".class, new JsonDeserializer<", + this._dateTimeProvider.timeType, + ">() {" + ); + this.indent(() => { + this.emitLine("@Override"); + this.emitBlock( + [ + "public ", + this._dateTimeProvider.timeType, + " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", + "throws IOException, JsonProcessingException" + ], + () => { + this.emitLine("String value = jsonParser.getText();"); + this.emitLine("return ", this._dateTimeProvider.convertStringToTime("value"), ";"); + } + ); + }); + this.emitLine("});"); + } + + if (!this._dateTimeProvider.shouldEmitDateConverter) { + this.emitLine( + "module.addDeserializer(", + this._dateTimeProvider.dateType, + ".class, new JsonDeserializer<", + this._dateTimeProvider.dateType, + ">() {" + ); + this.indent(() => { + this.emitLine("@Override"); + this.emitBlock( + [ + "public ", + this._dateTimeProvider.dateType, + " deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) ", + "throws IOException, JsonProcessingException" + ], + () => { + this.emitLine("String value = jsonParser.getText();"); + this.emitLine("return ", this._dateTimeProvider.convertStringToDate("value"), ";"); + } + ); + }); + this.emitLine("});"); + } + + this.emitLine("mapper.registerModule(module);"); + } + + protected emitConverterClass(): void { + this.startFile(this._converterClassname); + this.emitCommentLines([ + "To use this code, add the following Maven dependency to your project:", + "", + this._options.lombok ? " org.projectlombok : lombok : 1.18.2" : "", + " com.fasterxml.jackson.core : jackson-databind : 2.9.0", + this._options.dateTimeProvider === "java8" + ? " com.fasterxml.jackson.datatype : jackson-datatype-jsr310 : 2.9.0" + : "", + "", + "Import this package:", + "" + ]); + this.emitLine("// import ", this._options.packageName, ".Converter;"); + this.emitMultiline(`// +// Then you can deserialize a JSON string with +//`); + this.forEachTopLevel("none", (t, name) => { + this.emitLine( + "// ", + this.javaType(false, t), + " data = Converter.", + this.decoderName(name), + "(jsonString);" + ); + }); + this.ensureBlankLine(); + const imports = [ + "java.io.IOException", + "com.fasterxml.jackson.databind.*", + "com.fasterxml.jackson.databind.module.SimpleModule", + "com.fasterxml.jackson.core.JsonParser", + "com.fasterxml.jackson.core.JsonProcessingException", + "java.util.*" + ].concat(this._dateTimeProvider.converterImports); + this.emitPackageAndImports(imports); + this.ensureBlankLine(); + this.emitBlock(["public class Converter"], () => { + this.emitLine("// Date-time helpers"); + this._dateTimeProvider.emitDateTimeConverters(); + + this.emitLine("// Serialize/deserialize helpers"); + this.forEachTopLevel("leading-and-interposing", (topLevelType, topLevelName) => { + const topLevelTypeRendered = this.javaType(false, topLevelType); + this.emitBlock( + [ + "public static ", + topLevelTypeRendered, + " ", + this.decoderName(topLevelName), + "(String json) throws IOException" + ], + () => { + this.emitLine("return ", this.readerGetterName(topLevelName), "().readValue(json);"); + } + ); + this.ensureBlankLine(); + this.emitBlock( + [ + "public static String ", + this.encoderName(topLevelName), + "(", + topLevelTypeRendered, + " obj) throws JsonProcessingException" + ], + () => { + this.emitLine("return ", this.writerGetterName(topLevelName), "().writeValueAsString(obj);"); + } + ); + }); + this.forEachTopLevel("leading-and-interposing", (topLevelType, topLevelName) => { + const readerName = this.fieldOrMethodName("reader", topLevelName); + const writerName = this.fieldOrMethodName("writer", topLevelName); + this.emitLine("private static ObjectReader ", readerName, ";"); + this.emitLine("private static ObjectWriter ", writerName, ";"); + this.ensureBlankLine(); + this.emitBlock( + ["private static void ", this.methodName("instantiate", "Mapper", topLevelName), "()"], + () => { + const renderedForClass = this.javaTypeWithoutGenerics(false, topLevelType); + this.emitLine("ObjectMapper mapper = new ObjectMapper();"); + this.emitLine("mapper.findAndRegisterModules();"); + this.emitLine("mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);"); + this.emitLine("mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);"); + this.emitOffsetDateTimeConverterModule(); + this.emitLine(readerName, " = mapper.readerFor(", renderedForClass, ".class);"); + this.emitLine(writerName, " = mapper.writerFor(", renderedForClass, ".class);"); + } + ); + this.ensureBlankLine(); + this.emitBlock(["private static ObjectReader ", this.readerGetterName(topLevelName), "()"], () => { + this.emitLine( + "if (", + readerName, + " == null) ", + this.methodName("instantiate", "Mapper", topLevelName), + "();" + ); + this.emitLine("return ", readerName, ";"); + }); + this.ensureBlankLine(); + this.emitBlock(["private static ObjectWriter ", this.writerGetterName(topLevelName), "()"], () => { + this.emitLine( + "if (", + writerName, + " == null) ", + this.methodName("instantiate", "Mapper", topLevelName), + "();" + ); + this.emitLine("return ", writerName, ";"); + }); + }); + }); + this.finishFile(); + } + + protected emitSourceStructure(): void { + this.emitConverterClass(); + super.emitSourceStructure(); + } +} diff --git a/packages/quicktype-core/src/language/Java/JavaRenderer.ts b/packages/quicktype-core/src/language/Java/JavaRenderer.ts new file mode 100644 index 000000000..6335e60fb --- /dev/null +++ b/packages/quicktype-core/src/language/Java/JavaRenderer.ts @@ -0,0 +1,514 @@ +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { acronymStyle } from "../../support/Acronyms"; +import { capitalize, stringEscape } from "../../support/Strings"; +import { assert, assertNever, defined } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, type Type, UnionType } from "../../Type"; +import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { javaKeywords } from "./constants"; +import { Java8DateTimeProvider, type JavaDateTimeProvider, JavaLegacyDateTimeProvider } from "./DateTimeProvider"; +import { type javaOptions } from "./language"; +import { javaNameStyle } from "./utils"; + +export class JavaRenderer extends ConvenienceRenderer { + private _currentFilename: string | undefined; + + private readonly _gettersAndSettersForPropertyName = new Map(); + + private _haveEmittedLeadingComments = false; + + protected readonly _dateTimeProvider: JavaDateTimeProvider; + + protected readonly _converterClassname: string = "Converter"; + + protected readonly _converterKeywords: string[] = []; + + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + protected readonly _options: OptionValues + ) { + super(targetLanguage, renderContext); + + switch (_options.dateTimeProvider) { + default: + case "java8": + this._dateTimeProvider = new Java8DateTimeProvider(this, this._converterClassname); + break; + case "legacy": + this._dateTimeProvider = new JavaLegacyDateTimeProvider(this, this._converterClassname); + break; + } + } + + protected forbiddenNamesForGlobalNamespace(): string[] { + const keywords = [ + ...javaKeywords, + ...this._converterKeywords, + this._converterClassname, + ...this._dateTimeProvider.keywords + ]; + return keywords; + } + + protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + return { names: [], includeGlobalForbidden: true }; + } + + protected makeNamedTypeNamer(): Namer { + return this.getNameStyling("typeNamingFunction"); + } + + protected namerForObjectProperty(): Namer { + return this.getNameStyling("propertyNamingFunction"); + } + + protected makeUnionMemberNamer(): Namer { + return this.getNameStyling("propertyNamingFunction"); + } + + protected makeEnumCaseNamer(): Namer { + return this.getNameStyling("enumCaseNamingFunction"); + } + + protected unionNeedsName(u: UnionType): boolean { + return nullableFromUnion(u) === null; + } + + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + // If the top-level type doesn't contain any classes or unions + // we have to define a class just for the `FromJson` method, in + // emitFromJsonForTopLevel. + return directlyReachableSingleNamedType(type); + } + + protected makeNamesForPropertyGetterAndSetter( + _c: ClassType, + _className: Name, + _p: ClassProperty, + _jsonName: string, + name: Name + ): [Name, Name] { + const getterName = new DependencyName( + this.getNameStyling("propertyNamingFunction"), + name.order, + lookup => `get_${lookup(name)}` + ); + const setterName = new DependencyName( + this.getNameStyling("propertyNamingFunction"), + name.order, + lookup => `set_${lookup(name)}` + ); + return [getterName, setterName]; + } + + protected makePropertyDependencyNames( + c: ClassType, + className: Name, + p: ClassProperty, + jsonName: string, + name: Name + ): Name[] { + const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); + this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); + return getterAndSetterNames; + } + + private getNameStyling(convention: string): Namer { + const styling: { [key: string]: Namer } = { + typeNamingFunction: funPrefixNamer("types", n => + javaNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)) + ), + propertyNamingFunction: funPrefixNamer("properties", n => + javaNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)) + ), + enumCaseNamingFunction: funPrefixNamer("enum-cases", n => + javaNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)) + ) + }; + return styling[convention]; + } + + protected fieldOrMethodName(methodName: string, topLevelName: Name): Sourcelike { + if (this.topLevels.size === 1) { + return methodName; + } + + return [topLevelName, capitalize(methodName)]; + } + + protected methodName(prefix: string, suffix: string, topLevelName: Name): Sourcelike { + if (this.topLevels.size === 1) { + return [prefix, suffix]; + } + + return [prefix, topLevelName, suffix]; + } + + protected decoderName(topLevelName: Name): Sourcelike { + return this.fieldOrMethodName("fromJsonString", topLevelName); + } + + protected encoderName(topLevelName: Name): Sourcelike { + return this.fieldOrMethodName("toJsonString", topLevelName); + } + + protected readerGetterName(topLevelName: Name): Sourcelike { + return this.methodName("get", "ObjectReader", topLevelName); + } + + protected writerGetterName(topLevelName: Name): Sourcelike { + return this.methodName("get", "ObjectWriter", topLevelName); + } + + protected startFile(basename: Sourcelike): void { + assert(this._currentFilename === undefined, "Previous file wasn't finished"); + // FIXME: The filenames should actually be Sourcelikes, too + this._currentFilename = `${this.sourcelikeToString(basename)}.java`; + // FIXME: Why is this necessary? + this.ensureBlankLine(); + if (!this._haveEmittedLeadingComments && this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + this.ensureBlankLine(); + this._haveEmittedLeadingComments = true; + } + } + + protected finishFile(): void { + super.finishFile(defined(this._currentFilename)); + this._currentFilename = undefined; + } + + protected emitPackageAndImports(imports: string[]): void { + this.emitLine("package ", this._options.packageName, ";"); + this.ensureBlankLine(); + for (const pkg of imports) { + this.emitLine("import ", pkg, ";"); + } + } + + protected emitFileHeader(fileName: Sourcelike, imports: string[]): void { + this.startFile(fileName); + this.emitPackageAndImports(imports); + this.ensureBlankLine(); + } + + public emitDescriptionBlock(lines: Sourcelike[]): void { + this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + } + + public emitBlock(line: Sourcelike, f: () => void): void { + this.emitLine(line, " {"); + this.indent(f); + this.emitLine("}"); + } + + public emitTryCatch(main: () => void, handler: () => void, exception = "Exception"): void { + this.emitLine("try {"); + this.indent(main); + this.emitLine("} catch (", exception, " ex) {"); + this.indent(handler); + this.emitLine("}"); + } + + public emitIgnoredTryCatchBlock(f: () => void): void { + this.emitTryCatch(f, () => this.emitLine("// Ignored")); + } + + protected javaType(reference: boolean, t: Type, withIssues = false): Sourcelike { + return matchType( + t, + _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "Object"), + _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, "Object"), + _boolType => (reference ? "Boolean" : "boolean"), + _integerType => (reference ? "Long" : "long"), + _doubleType => (reference ? "Double" : "double"), + _stringType => "String", + arrayType => { + if (this._options.useList) { + return ["List<", this.javaType(true, arrayType.items, withIssues), ">"]; + } else { + return [this.javaType(false, arrayType.items, withIssues), "[]"]; + } + }, + classType => this.nameForNamedType(classType), + mapType => ["Map"], + enumType => this.nameForNamedType(enumType), + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) return this.javaType(true, nullable, withIssues); + return this.nameForNamedType(unionType); + }, + transformedStringType => { + if (transformedStringType.kind === "time") { + return this._dateTimeProvider.timeType; + } + + if (transformedStringType.kind === "date") { + return this._dateTimeProvider.dateType; + } + + if (transformedStringType.kind === "date-time") { + return this._dateTimeProvider.dateTimeType; + } + + if (transformedStringType.kind === "uuid") { + return "UUID"; + } + + return "String"; + } + ); + } + + protected javaImport(t: Type): string[] { + return matchType( + t, + _anyType => [], + _nullType => [], + _boolType => [], + _integerType => [], + _doubleType => [], + _stringType => [], + arrayType => { + if (this._options.useList) { + return [...this.javaImport(arrayType.items), "java.util.List"]; + } else { + return [...this.javaImport(arrayType.items)]; + } + }, + _classType => [], + mapType => [...this.javaImport(mapType.values), "java.util.Map"], + _enumType => [], + unionType => { + const imports: string[] = []; + unionType.members.forEach(type => this.javaImport(type).forEach(imp => imports.push(imp))); + return imports; + }, + transformedStringType => { + if (transformedStringType.kind === "time") { + return this._dateTimeProvider.timeImports; + } + + if (transformedStringType.kind === "date") { + return this._dateTimeProvider.dateImports; + } + + if (transformedStringType.kind === "date-time") { + return this._dateTimeProvider.dateTimeImports; + } + + if (transformedStringType.kind === "uuid") { + return ["java.util.UUID"]; + } + + return []; + } + ); + } + + protected javaTypeWithoutGenerics(reference: boolean, t: Type): Sourcelike { + if (t instanceof ArrayType) { + if (this._options.useList) { + return ["List"]; + } else { + return [this.javaTypeWithoutGenerics(false, t.items), "[]"]; + } + } else if (t instanceof MapType) { + return "Map"; + } else if (t instanceof UnionType) { + const nullable = nullableFromUnion(t); + if (nullable !== null) return this.javaTypeWithoutGenerics(true, nullable); + return this.nameForNamedType(t); + } else { + return this.javaType(reference, t); + } + } + + protected emitClassAttributes(_c: ClassType, _className: Name): void { + if (this._options.lombok) { + this.emitLine("@lombok.Data"); + } + } + + protected annotationsForAccessor( + _c: ClassType, + _className: Name, + _propertyName: Name, + _jsonName: string, + _p: ClassProperty, + _isSetter: boolean + ): string[] { + return []; + } + + protected importsForType(t: ClassType | UnionType | EnumType): string[] { + if (t instanceof ClassType) { + return []; + } + + if (t instanceof UnionType) { + return ["java.io.IOException"]; + } + + if (t instanceof EnumType) { + return ["java.io.IOException"]; + } + + return assertNever(t); + } + + protected importsForClass(c: ClassType): string[] { + const imports: string[] = []; + this.forEachClassProperty(c, "none", (_name, _jsonName, p) => { + this.javaImport(p.type).forEach(imp => imports.push(imp)); + }); + imports.sort(); + return [...new Set(imports)]; + } + + protected importsForUnionMembers(u: UnionType): string[] { + const imports: string[] = []; + const [, nonNulls] = removeNullFromUnion(u); + this.forEachUnionMember(u, nonNulls, "none", null, (_fieldName, t) => { + this.javaImport(t).forEach(imp => imports.push(imp)); + }); + imports.sort(); + return [...new Set(imports)]; + } + + protected emitClassDefinition(c: ClassType, className: Name): void { + let imports = [...this.importsForType(c), ...this.importsForClass(c)]; + + this.emitFileHeader(className, imports); + this.emitDescription(this.descriptionForType(c)); + this.emitClassAttributes(c, className); + this.emitBlock(["public class ", className], () => { + this.forEachClassProperty(c, "none", (name, jsonName, p) => { + if (this._options.lombok && this._options.lombokCopyAnnotations) { + const getter = this.annotationsForAccessor(c, className, name, jsonName, p, false); + const setter = this.annotationsForAccessor(c, className, name, jsonName, p, true); + if (getter.length !== 0) { + this.emitLine("@lombok.Getter(onMethod_ = {" + getter.join(", ") + "})"); + } + + if (setter.length !== 0) { + this.emitLine("@lombok.Setter(onMethod_ = {" + setter.join(", ") + "})"); + } + } + + this.emitLine("private ", this.javaType(false, p.type, true), " ", name, ";"); + }); + if (!this._options.lombok) { + this.forEachClassProperty(c, "leading-and-interposing", (name, jsonName, p) => { + this.emitDescription(this.descriptionForClassProperty(c, jsonName)); + const [getterName, setterName] = defined(this._gettersAndSettersForPropertyName.get(name)); + const rendered = this.javaType(false, p.type); + this.annotationsForAccessor(c, className, name, jsonName, p, false).forEach(annotation => + this.emitLine(annotation) + ); + this.emitLine("public ", rendered, " ", getterName, "() { return ", name, "; }"); + this.annotationsForAccessor(c, className, name, jsonName, p, true).forEach(annotation => + this.emitLine(annotation) + ); + this.emitLine("public void ", setterName, "(", rendered, " value) { this.", name, " = value; }"); + }); + } + }); + this.finishFile(); + } + + protected unionField(u: UnionType, t: Type, withIssues = false): { fieldName: Sourcelike; fieldType: Sourcelike } { + const fieldType = this.javaType(true, t, withIssues); + // FIXME: "Value" should be part of the name. + const fieldName = [this.nameForUnionMember(u, t), "Value"]; + return { fieldType, fieldName }; + } + + protected emitUnionAttributes(_u: UnionType, _unionName: Name): void { + // empty + } + + protected emitUnionSerializer(_u: UnionType, _unionName: Name): void { + // empty + } + + protected emitUnionDefinition(u: UnionType, unionName: Name): void { + const imports = [...this.importsForType(u), ...this.importsForUnionMembers(u)]; + + this.emitFileHeader(unionName, imports); + this.emitDescription(this.descriptionForType(u)); + const [, nonNulls] = removeNullFromUnion(u); + + this.emitUnionAttributes(u, unionName); + this.emitBlock(["public class ", unionName], () => { + for (const t of nonNulls) { + const { fieldType, fieldName } = this.unionField(u, t, true); + this.emitLine("public ", fieldType, " ", fieldName, ";"); + } + + this.emitUnionSerializer(u, unionName); + }); + this.finishFile(); + } + + protected emitEnumSerializationAttributes(_e: EnumType): void { + // Empty + } + + protected emitEnumDeserializationAttributes(_e: EnumType): void { + // Empty + } + + protected emitEnumDefinition(e: EnumType, enumName: Name): void { + this.emitFileHeader(enumName, this.importsForType(e)); + this.emitDescription(this.descriptionForType(e)); + const caseNames: Sourcelike[] = []; + this.forEachEnumCase(e, "none", name => { + if (caseNames.length > 0) caseNames.push(", "); + caseNames.push(name); + }); + caseNames.push(";"); + this.emitBlock(["public enum ", enumName], () => { + this.emitLine(caseNames); + this.ensureBlankLine(); + + this.emitEnumSerializationAttributes(e); + this.emitBlock("public String toValue()", () => { + this.emitLine("switch (this) {"); + this.indent(() => { + this.forEachEnumCase(e, "none", (name, jsonName) => { + this.emitLine("case ", name, ': return "', stringEscape(jsonName), '";'); + }); + }); + this.emitLine("}"); + this.emitLine("return null;"); + }); + this.ensureBlankLine(); + + this.emitEnumDeserializationAttributes(e); + this.emitBlock(["public static ", enumName, " forValue(String value) throws IOException"], () => { + this.forEachEnumCase(e, "none", (name, jsonName) => { + this.emitLine('if (value.equals("', stringEscape(jsonName), '")) return ', name, ";"); + }); + this.emitLine('throw new IOException("Cannot deserialize ', enumName, '");'); + }); + }); + this.finishFile(); + } + + protected emitSourceStructure(): void { + this.forEachNamedType( + "leading-and-interposing", + (c: ClassType, n: Name) => this.emitClassDefinition(c, n), + (e, n) => this.emitEnumDefinition(e, n), + (u, n) => this.emitUnionDefinition(u, n) + ); + } +} diff --git a/packages/quicktype-core/src/language/Java/constants.ts b/packages/quicktype-core/src/language/Java/constants.ts new file mode 100644 index 000000000..d1e2f797e --- /dev/null +++ b/packages/quicktype-core/src/language/Java/constants.ts @@ -0,0 +1,69 @@ +export const javaKeywords = [ + "_", // as of release 9, '_' is a keyword, and may not be used as an identifier + "Object", + "Class", + "System", + "Long", + "Double", + "Boolean", + "String", + "List", + "Map", + "UUID", + "Exception", + "IOException", + "Override", + "abstract", + "continue", + "for", + "new", + "switch", + "assert", + "default", + "goto", + "package", + "synchronized", + "boolean", + "do", + "if", + "private", + "this", + "break", + "double", + "implements", + "protected", + "throw", + "byte", + "else", + "import", + "public", + "throws", + "case", + "enum", + "instanceof", + "return", + "transient", + "catch", + "extends", + "int", + "short", + "try", + "char", + "final", + "interface", + "static", + "void", + "class", + "finally", + "long", + "strictfp", + "volatile", + "const", + "float", + "native", + "super", + "while", + "null", + "false", + "true" +] as const; diff --git a/packages/quicktype-core/src/language/Java/index.ts b/packages/quicktype-core/src/language/Java/index.ts new file mode 100644 index 000000000..ea2ba695e --- /dev/null +++ b/packages/quicktype-core/src/language/Java/index.ts @@ -0,0 +1,3 @@ +export { JavaTargetLanguage, javaOptions } from "./language"; +export { JavaRenderer } from "./JavaRenderer"; +export { JacksonRenderer } from "./JavaJacksonRenderer"; diff --git a/packages/quicktype-core/src/language/Java/language.ts b/packages/quicktype-core/src/language/Java/language.ts new file mode 100644 index 000000000..3d22278b5 --- /dev/null +++ b/packages/quicktype-core/src/language/Java/language.ts @@ -0,0 +1,77 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { JacksonRenderer } from "./JavaJacksonRenderer"; +import { JavaRenderer } from "./JavaRenderer"; + +export const javaOptions = { + useList: new EnumOption( + "array-type", + "Use T[] or List", + [ + ["array", false], + ["list", true] + ], + "array" + ), + justTypes: new BooleanOption("just-types", "Plain types only", false), + dateTimeProvider: new EnumOption( + "datetime-provider", + "Date time provider type", + [ + ["java8", "java8"], + ["legacy", "legacy"] + ], + "java8" + ), + acronymStyle: acronymOption(AcronymStyleOptions.Pascal), + // FIXME: Do this via a configurable named eventually. + packageName: new StringOption("package", "Generated package name", "NAME", "io.quicktype"), + lombok: new BooleanOption("lombok", "Use lombok", false, "primary"), + lombokCopyAnnotations: new BooleanOption("lombok-copy-annotations", "Copy accessor annotations", true, "secondary") +}; + +export class JavaTargetLanguage extends TargetLanguage { + public constructor() { + super("Java", ["java"], "java"); + } + + protected getOptions(): Array> { + return [ + javaOptions.useList, + javaOptions.justTypes, + javaOptions.dateTimeProvider, + javaOptions.acronymStyle, + javaOptions.packageName, + javaOptions.lombok, + javaOptions.lombokCopyAnnotations + ]; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): JavaRenderer { + const options = getOptionValues(javaOptions, untypedOptionValues); + if (options.justTypes) { + return new JavaRenderer(this, renderContext, options); + } + + return new JacksonRenderer(this, renderContext, options); + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + mapping.set("date", "date"); + mapping.set("time", "time"); + mapping.set("date-time", "date-time"); + mapping.set("uuid", "uuid"); + return mapping; + } +} diff --git a/packages/quicktype-core/src/language/Java/utils.ts b/packages/quicktype-core/src/language/Java/utils.ts new file mode 100644 index 000000000..abc461f47 --- /dev/null +++ b/packages/quicktype-core/src/language/Java/utils.ts @@ -0,0 +1,46 @@ +import { + allLowerWordStyle, + allUpperWordStyle, + combineWords, + escapeNonPrintableMapper, + firstUpperWordStyle, + isAscii, + isDigit, + isLetter, + splitIntoWords, + standardUnicodeHexEscape, + utf16ConcatMap, + utf16LegalizeCharacters +} from "../../support/Strings"; + +export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); + +function isStartCharacter(codePoint: number): boolean { + if (codePoint === 0x5f) return true; // underscore + return isAscii(codePoint) && isLetter(codePoint); +} + +function isPartCharacter(codePoint: number): boolean { + return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); +} + +const legalizeName = utf16LegalizeCharacters(isPartCharacter); + +export function javaNameStyle( + startWithUpper: boolean, + upperUnderscore: boolean, + original: string, + acronymsStyle: (s: string) => string = allUpperWordStyle +): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + upperUnderscore ? allUpperWordStyle : startWithUpper ? firstUpperWordStyle : allLowerWordStyle, + upperUnderscore ? allUpperWordStyle : firstUpperWordStyle, + upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, + acronymsStyle, + upperUnderscore ? "_" : "", + isStartCharacter + ); +} From 96f0901e8d260ddb21f320d9bef12848b8bda4f2 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:30:30 -0700 Subject: [PATCH 56/80] move Haskell to own dir --- .../HaskellRenderer.ts} | 148 ++---------------- .../src/language/Haskell/constants.ts | 54 +++++++ .../src/language/Haskell/index.ts | 2 + .../src/language/Haskell/language.ts | 37 +++++ .../src/language/Haskell/utils.ts | 31 ++++ 5 files changed, 138 insertions(+), 134 deletions(-) rename packages/quicktype-core/src/language/{Haskell.ts => Haskell/HaskellRenderer.ts} (82%) create mode 100644 packages/quicktype-core/src/language/Haskell/constants.ts create mode 100644 packages/quicktype-core/src/language/Haskell/index.ts create mode 100644 packages/quicktype-core/src/language/Haskell/language.ts create mode 100644 packages/quicktype-core/src/language/Haskell/utils.ts diff --git a/packages/quicktype-core/src/language/Haskell.ts b/packages/quicktype-core/src/language/Haskell/HaskellRenderer.ts similarity index 82% rename from packages/quicktype-core/src/language/Haskell.ts rename to packages/quicktype-core/src/language/Haskell/HaskellRenderer.ts index 16cd16a35..b5a2143b4 100644 --- a/packages/quicktype-core/src/language/Haskell.ts +++ b/packages/quicktype-core/src/language/Haskell/HaskellRenderer.ts @@ -1,138 +1,18 @@ import { mapContains } from "collection-utils"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { - BooleanOption, - EnumOption, - type Option, - type OptionValues, - StringOption, - getOptionValues -} from "../RendererOptions"; -import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../Source"; -import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - firstUpperWordStyle, - isAscii, - isLetterOrUnderscore, - isLetterOrUnderscoreOrDigit, - legalizeCharacters, - splitIntoWords, - stringEscape -} from "../support/Strings"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion } from "../TypeUtils"; - -export const haskellOptions = { - justTypes: new BooleanOption("just-types", "Plain types only", false), - useList: new EnumOption("array-type", "Use Array or List", [ - ["array", false], - ["list", true] - ]), - moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") -}; - -export class HaskellTargetLanguage extends TargetLanguage { - public constructor() { - super("Haskell", ["haskell"], "haskell"); - } - - protected getOptions(): Array> { - return [haskellOptions.justTypes, haskellOptions.moduleName, haskellOptions.useList]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): HaskellRenderer { - return new HaskellRenderer(this, renderContext, getOptionValues(haskellOptions, untypedOptionValues)); - } -} - -const forbiddenNames = [ - // reserved keywords - "as", - "case", - "class", - "data", - "default", - "deriving", - "do", - "else", - "family", - "forall", - "foreign", - "hiding", - "if", - "import", - "in", - "infix", - "infixl", - "infixr", - "instance", - "let", - "of", - "mdo", - "module", - "newtype", - "proc", - "qualified", - "rec", - "then", - "type", - "where", - // in Prelude keywords ... - "id", - "Array", - "HashMap", - "Map", - "Maybe", - "Bool", - "Int", - "True", - "False", - "Enum", - // Aeson types - "encode", - "decode", - "text", - "Text", - "Value", - "Object", - "Result", - "Series", - "Error" -]; - -const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); - -function haskellNameStyle(original: string, upper: boolean): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - upper ? firstUpperWordStyle : allLowerWordStyle, - firstUpperWordStyle, - upper ? allUpperWordStyle : allLowerWordStyle, - allUpperWordStyle, - "", - isLetterOrUnderscore - ); -} - -const upperNamingFunction = funPrefixNamer("upper", n => haskellNameStyle(n, true)); -const lowerNamingFunction = funPrefixNamer("lower", n => haskellNameStyle(n, false)); +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../../Source"; +import { stringEscape } from "../../support/Strings"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../../Type"; +import { matchType, nullableFromUnion } from "../../TypeUtils"; + +import { forbiddenNames } from "./constants"; +import { type haskellOptions } from "./language"; +import { lowerNamingFunction, upperNamingFunction } from "./utils"; export class HaskellRenderer extends ConvenienceRenderer { public constructor( @@ -143,7 +23,7 @@ export class HaskellRenderer extends ConvenienceRenderer { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return forbiddenNames; } diff --git a/packages/quicktype-core/src/language/Haskell/constants.ts b/packages/quicktype-core/src/language/Haskell/constants.ts new file mode 100644 index 000000000..5e09e6702 --- /dev/null +++ b/packages/quicktype-core/src/language/Haskell/constants.ts @@ -0,0 +1,54 @@ +export const forbiddenNames = [ + // reserved keywords + "as", + "case", + "class", + "data", + "default", + "deriving", + "do", + "else", + "family", + "forall", + "foreign", + "hiding", + "if", + "import", + "in", + "infix", + "infixl", + "infixr", + "instance", + "let", + "of", + "mdo", + "module", + "newtype", + "proc", + "qualified", + "rec", + "then", + "type", + "where", + // in Prelude keywords ... + "id", + "Array", + "HashMap", + "Map", + "Maybe", + "Bool", + "Int", + "True", + "False", + "Enum", + // Aeson types + "encode", + "decode", + "text", + "Text", + "Value", + "Object", + "Result", + "Series", + "Error" +] as const; diff --git a/packages/quicktype-core/src/language/Haskell/index.ts b/packages/quicktype-core/src/language/Haskell/index.ts new file mode 100644 index 000000000..9658076f0 --- /dev/null +++ b/packages/quicktype-core/src/language/Haskell/index.ts @@ -0,0 +1,2 @@ +export { HaskellTargetLanguage, haskellOptions } from "./language"; +export { HaskellRenderer } from "./HaskellRenderer"; diff --git a/packages/quicktype-core/src/language/Haskell/language.ts b/packages/quicktype-core/src/language/Haskell/language.ts new file mode 100644 index 000000000..84ad167f3 --- /dev/null +++ b/packages/quicktype-core/src/language/Haskell/language.ts @@ -0,0 +1,37 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { HaskellRenderer } from "./HaskellRenderer"; + +export const haskellOptions = { + justTypes: new BooleanOption("just-types", "Plain types only", false), + useList: new EnumOption("array-type", "Use Array or List", [ + ["array", false], + ["list", true] + ]), + moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") +}; + +export class HaskellTargetLanguage extends TargetLanguage { + public constructor() { + super("Haskell", ["haskell"], "haskell"); + } + + protected getOptions(): Array> { + return [haskellOptions.justTypes, haskellOptions.moduleName, haskellOptions.useList]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): HaskellRenderer { + return new HaskellRenderer(this, renderContext, getOptionValues(haskellOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/Haskell/utils.ts b/packages/quicktype-core/src/language/Haskell/utils.ts new file mode 100644 index 000000000..951c83760 --- /dev/null +++ b/packages/quicktype-core/src/language/Haskell/utils.ts @@ -0,0 +1,31 @@ +import { funPrefixNamer } from "../../Naming"; +import { + legalizeCharacters, + isLetterOrUnderscoreOrDigit, + isLetterOrUnderscore, + isAscii, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allLowerWordStyle, + allUpperWordStyle +} from "../../support/Strings"; + +const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); + +function haskellNameStyle(original: string, upper: boolean): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + upper ? firstUpperWordStyle : allLowerWordStyle, + firstUpperWordStyle, + upper ? allUpperWordStyle : allLowerWordStyle, + allUpperWordStyle, + "", + isLetterOrUnderscore + ); +} + +export const upperNamingFunction = funPrefixNamer("upper", n => haskellNameStyle(n, true)); +export const lowerNamingFunction = funPrefixNamer("lower", n => haskellNameStyle(n, false)); From 6bf4a1190fa802bf7d7657f5f12b37a1085796d8 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:33:17 -0700 Subject: [PATCH 57/80] move Golang to own dir --- .../{Golang.ts => Golang/GolangRenderer.ts} | 336 +++++++----------- .../src/language/Golang/index.ts | 0 .../src/language/Golang/language.ts | 60 ++++ .../src/language/Golang/utils.ts | 44 +++ 4 files changed, 225 insertions(+), 215 deletions(-) rename packages/quicktype-core/src/language/{Golang.ts => Golang/GolangRenderer.ts} (73%) create mode 100644 packages/quicktype-core/src/language/Golang/index.ts create mode 100644 packages/quicktype-core/src/language/Golang/language.ts create mode 100644 packages/quicktype-core/src/language/Golang/utils.ts diff --git a/packages/quicktype-core/src/language/Golang.ts b/packages/quicktype-core/src/language/Golang/GolangRenderer.ts similarity index 73% rename from packages/quicktype-core/src/language/Golang.ts rename to packages/quicktype-core/src/language/Golang/GolangRenderer.ts index 9a2081af6..708666452 100644 --- a/packages/quicktype-core/src/language/Golang.ts +++ b/packages/quicktype-core/src/language/Golang/GolangRenderer.ts @@ -1,111 +1,17 @@ -import { type PrimitiveStringTypeKind, type StringTypeMapping, type TransformedStringTypeKind } from ".."; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer } from "../ConvenienceRenderer"; -import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; -import { - allUpperWordStyle, - camelCase, - combineWords, - firstUpperWordStyle, - isLetterOrUnderscore, - isLetterOrUnderscoreOrDigit, - legalizeCharacters, - splitIntoWords, - stringEscape -} from "../support/Strings"; -import { assert, defined } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type EnumType, type Type, type TypeKind, UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export const goOptions = { - justTypes: new BooleanOption("just-types", "Plain types only", false), - justTypesAndPackage: new BooleanOption("just-types-and-package", "Plain types with package only", false), - packageName: new StringOption("package", "Generated package name", "NAME", "main"), - multiFileOutput: new BooleanOption("multi-file-output", "Renders each top-level object in its own Go file", false), - fieldTags: new StringOption("field-tags", "list of tags which should be generated for fields", "TAGS", "json"), - omitEmpty: new BooleanOption( - "omit-empty", - 'If set, all non-required objects will be tagged with ",omitempty"', - false - ) -}; - -export class GoTargetLanguage extends TargetLanguage { - public constructor() { - super("Go", ["go", "golang"], "go"); - } - - protected getOptions(): Array> { - return [ - goOptions.justTypes, - goOptions.justTypesAndPackage, - goOptions.packageName, - goOptions.multiFileOutput, - goOptions.fieldTags, - goOptions.omitEmpty - ]; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - mapping.set("date-time", "date-time"); - return mapping; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): GoRenderer { - return new GoRenderer(this, renderContext, getOptionValues(goOptions, untypedOptionValues)); - } - - protected get defaultIndentation(): string { - return "\t"; - } -} - -const namingFunction = funPrefixNamer("namer", goNameStyle); - -const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); - -function goNameStyle(original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - firstUpperWordStyle, - firstUpperWordStyle, - allUpperWordStyle, - allUpperWordStyle, - "", - isLetterOrUnderscore - ); -} - -const primitiveValueTypeKinds: TypeKind[] = ["integer", "double", "bool", "string"]; -const compoundTypeKinds: TypeKind[] = ["array", "class", "map", "enum"]; - -function isValueType(t: Type): boolean { - const kind = t.kind; - return primitiveValueTypeKinds.includes(kind) || kind === "class" || kind === "enum" || kind === "date-time"; -} - -function canOmitEmpty(cp: ClassProperty, omitEmptyOption: boolean): boolean { - if (!cp.isOptional) return false; - if (omitEmptyOption) return true; - const t = cp.type; - return !["union", "null", "any"].includes(t.kind); -} +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../../Source"; +import { camelCase, stringEscape } from "../../support/Strings"; +import { assert, defined } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassProperty, type ClassType, type EnumType, type Type, type TypeKind, UnionType } from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { type goOptions } from "./language"; +import { canOmitEmpty, compoundTypeKinds, isValueType, namingFunction, primitiveValueTypeKinds } from "./utils"; export class GoRenderer extends ConvenienceRenderer { private readonly _topLevelUnmarshalNames = new Map(); @@ -495,117 +401,117 @@ export class GoRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this .emitMultiline(`func unmarshalUnion(data []byte, pi **int64, pf **float64, pb **bool, ps **string, haveArray bool, pa interface{}, haveObject bool, pc interface{}, haveMap bool, pm interface{}, haveEnum bool, pe interface{}, nullable bool) (bool, error) { - if pi != nil { - *pi = nil - } - if pf != nil { - *pf = nil - } - if pb != nil { - *pb = nil - } - if ps != nil { - *ps = nil - } - - dec := json.NewDecoder(bytes.NewReader(data)) - dec.UseNumber() - tok, err := dec.Token() - if err != nil { - return false, err - } - - switch v := tok.(type) { - case json.Number: - if pi != nil { - i, err := v.Int64() - if err == nil { - *pi = &i - return false, nil - } - } - if pf != nil { - f, err := v.Float64() - if err == nil { - *pf = &f - return false, nil - } - return false, errors.New("Unparsable number") - } - return false, errors.New("Union does not contain number") - case float64: - return false, errors.New("Decoder should not return float64") - case bool: - if pb != nil { - *pb = &v - return false, nil - } - return false, errors.New("Union does not contain bool") - case string: - if haveEnum { - return false, json.Unmarshal(data, pe) - } - if ps != nil { - *ps = &v - return false, nil - } - return false, errors.New("Union does not contain string") - case nil: - if nullable { - return false, nil - } - return false, errors.New("Union does not contain null") - case json.Delim: - if v == '{' { - if haveObject { - return true, json.Unmarshal(data, pc) - } - if haveMap { - return false, json.Unmarshal(data, pm) - } - return false, errors.New("Union does not contain object") - } - if v == '[' { - if haveArray { - return false, json.Unmarshal(data, pa) - } - return false, errors.New("Union does not contain array") - } - return false, errors.New("Cannot handle delimiter") - } - return false, errors.New("Cannot unmarshal union") + if pi != nil { + *pi = nil + } + if pf != nil { + *pf = nil + } + if pb != nil { + *pb = nil + } + if ps != nil { + *ps = nil + } + + dec := json.NewDecoder(bytes.NewReader(data)) + dec.UseNumber() + tok, err := dec.Token() + if err != nil { + return false, err + } + + switch v := tok.(type) { + case json.Number: + if pi != nil { + i, err := v.Int64() + if err == nil { + *pi = &i + return false, nil + } + } + if pf != nil { + f, err := v.Float64() + if err == nil { + *pf = &f + return false, nil + } + return false, errors.New("Unparsable number") + } + return false, errors.New("Union does not contain number") + case float64: + return false, errors.New("Decoder should not return float64") + case bool: + if pb != nil { + *pb = &v + return false, nil + } + return false, errors.New("Union does not contain bool") + case string: + if haveEnum { + return false, json.Unmarshal(data, pe) + } + if ps != nil { + *ps = &v + return false, nil + } + return false, errors.New("Union does not contain string") + case nil: + if nullable { + return false, nil + } + return false, errors.New("Union does not contain null") + case json.Delim: + if v == '{' { + if haveObject { + return true, json.Unmarshal(data, pc) + } + if haveMap { + return false, json.Unmarshal(data, pm) + } + return false, errors.New("Union does not contain object") + } + if v == '[' { + if haveArray { + return false, json.Unmarshal(data, pa) + } + return false, errors.New("Union does not contain array") + } + return false, errors.New("Cannot handle delimiter") + } + return false, errors.New("Cannot unmarshal union") } func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, pa interface{}, haveObject bool, pc interface{}, haveMap bool, pm interface{}, haveEnum bool, pe interface{}, nullable bool) ([]byte, error) { - if pi != nil { - return json.Marshal(*pi) - } - if pf != nil { - return json.Marshal(*pf) - } - if pb != nil { - return json.Marshal(*pb) - } - if ps != nil { - return json.Marshal(*ps) - } - if haveArray { - return json.Marshal(pa) - } - if haveObject { - return json.Marshal(pc) - } - if haveMap { - return json.Marshal(pm) - } - if haveEnum { - return json.Marshal(pe) - } - if nullable { - return json.Marshal(nil) - } - return nil, errors.New("Union must not be null") + if pi != nil { + return json.Marshal(*pi) + } + if pf != nil { + return json.Marshal(*pf) + } + if pb != nil { + return json.Marshal(*pb) + } + if ps != nil { + return json.Marshal(*ps) + } + if haveArray { + return json.Marshal(pa) + } + if haveObject { + return json.Marshal(pc) + } + if haveMap { + return json.Marshal(pm) + } + if haveEnum { + return json.Marshal(pe) + } + if nullable { + return json.Marshal(nil) + } + return nil, errors.New("Union must not be null") }`); this.endFile(); } diff --git a/packages/quicktype-core/src/language/Golang/index.ts b/packages/quicktype-core/src/language/Golang/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/quicktype-core/src/language/Golang/language.ts b/packages/quicktype-core/src/language/Golang/language.ts new file mode 100644 index 000000000..f38edff15 --- /dev/null +++ b/packages/quicktype-core/src/language/Golang/language.ts @@ -0,0 +1,60 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { GoRenderer } from "./GolangRenderer"; + +export const goOptions = { + justTypes: new BooleanOption("just-types", "Plain types only", false), + justTypesAndPackage: new BooleanOption("just-types-and-package", "Plain types with package only", false), + packageName: new StringOption("package", "Generated package name", "NAME", "main"), + multiFileOutput: new BooleanOption("multi-file-output", "Renders each top-level object in its own Go file", false), + fieldTags: new StringOption("field-tags", "list of tags which should be generated for fields", "TAGS", "json"), + omitEmpty: new BooleanOption( + "omit-empty", + 'If set, all non-required objects will be tagged with ",omitempty"', + false + ) +}; + +export class GoTargetLanguage extends TargetLanguage { + public constructor() { + super("Go", ["go", "golang"], "go"); + } + + protected getOptions(): Array> { + return [ + goOptions.justTypes, + goOptions.justTypesAndPackage, + goOptions.packageName, + goOptions.multiFileOutput, + goOptions.fieldTags, + goOptions.omitEmpty + ]; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + mapping.set("date-time", "date-time"); + return mapping; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): GoRenderer { + return new GoRenderer(this, renderContext, getOptionValues(goOptions, untypedOptionValues)); + } + + protected get defaultIndentation(): string { + return "\t"; + } +} diff --git a/packages/quicktype-core/src/language/Golang/utils.ts b/packages/quicktype-core/src/language/Golang/utils.ts new file mode 100644 index 000000000..94f4f5c8a --- /dev/null +++ b/packages/quicktype-core/src/language/Golang/utils.ts @@ -0,0 +1,44 @@ +import { TypeKind, Type, ClassProperty } from "../../Type"; +import { funPrefixNamer } from "../../Naming"; +import { + legalizeCharacters, + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allUpperWordStyle +} from "../../support/Strings"; + +export const namingFunction = funPrefixNamer("namer", goNameStyle); + +const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); + +function goNameStyle(original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + firstUpperWordStyle, + firstUpperWordStyle, + allUpperWordStyle, + allUpperWordStyle, + "", + isLetterOrUnderscore + ); +} + +export const primitiveValueTypeKinds: TypeKind[] = ["integer", "double", "bool", "string"]; +export const compoundTypeKinds: TypeKind[] = ["array", "class", "map", "enum"]; + +export function isValueType(t: Type): boolean { + const kind = t.kind; + return primitiveValueTypeKinds.indexOf(kind) >= 0 || kind === "class" || kind === "enum" || kind === "date-time"; +} + +export function canOmitEmpty(cp: ClassProperty, omitEmptyOption: boolean): boolean { + if (!cp.isOptional) return false; + if (omitEmptyOption) return true; + const t = cp.type; + return ["union", "null", "any"].indexOf(t.kind) < 0; +} From 2609b3c06f8127e5d216712e1d1d0226e6d6b3a4 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:35:54 -0700 Subject: [PATCH 58/80] move Elm to own dir --- .../language/{Elm.ts => Elm/ElmRenderer.ts} | 170 +++--------------- .../src/language/Elm/constants.ts | 40 +++++ .../quicktype-core/src/language/Elm/index.ts | 2 + .../src/language/Elm/language.ts | 38 ++++ .../quicktype-core/src/language/Elm/utils.ts | 52 ++++++ 5 files changed, 152 insertions(+), 150 deletions(-) rename packages/quicktype-core/src/language/{Elm.ts => Elm/ElmRenderer.ts} (84%) create mode 100644 packages/quicktype-core/src/language/Elm/constants.ts create mode 100644 packages/quicktype-core/src/language/Elm/index.ts create mode 100644 packages/quicktype-core/src/language/Elm/language.ts create mode 100644 packages/quicktype-core/src/language/Elm/utils.ts diff --git a/packages/quicktype-core/src/language/Elm.ts b/packages/quicktype-core/src/language/Elm/ElmRenderer.ts similarity index 84% rename from packages/quicktype-core/src/language/Elm.ts rename to packages/quicktype-core/src/language/Elm/ElmRenderer.ts index ced7837b4..8ae5a9d70 100644 --- a/packages/quicktype-core/src/language/Elm.ts +++ b/packages/quicktype-core/src/language/Elm/ElmRenderer.ts @@ -1,150 +1,20 @@ import { arrayIntercalate, mapContains } from "collection-utils"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { - BooleanOption, - EnumOption, - type Option, - type OptionValues, - StringOption, - getOptionValues -} from "../RendererOptions"; -import { type MultiWord, type Sourcelike, annotated, multiWord, parenIfNeeded, singleWord } from "../Source"; -import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - decapitalize, - firstUpperWordStyle, - isAscii, - isLetterOrUnderscore, - isLetterOrUnderscoreOrDigit, - legalizeCharacters, - splitIntoWords, - stringEscape -} from "../support/Strings"; -import { defined } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ClassProperty, type ClassType, type EnumType, type Type, UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion } from "../TypeUtils"; - -export const elmOptions = { - justTypes: new BooleanOption("just-types", "Plain types only", false), - useList: new EnumOption("array-type", "Use Array or List", [ - ["array", false], - ["list", true] - ]), - // FIXME: Do this via a configurable named eventually. - moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") -}; - -export class ElmTargetLanguage extends TargetLanguage { - public constructor() { - super("Elm", ["elm"], "elm"); - } - - protected getOptions(): Array> { - return [elmOptions.justTypes, elmOptions.moduleName, elmOptions.useList]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ElmRenderer { - return new ElmRenderer(this, renderContext, getOptionValues(elmOptions, untypedOptionValues)); - } -} - -const forbiddenNames = [ - "if", - "then", - "else", - "case", - "of", - "let", - "in", - "infix", - "type", - "module", - "where", - "import", - "exposing", - "as", - "port", - "int", - "float", - "bool", - "string", - "Jenc", - "Jdec", - "Jpipe", - "always", - "identity", - "Array", - "List", - "Dict", - "Maybe", - "map", - "toList", - "makeArrayEncoder", - "makeDictEncoder", - "makeNullableEncoder", - "Int", - "True", - "False", - "String", - "Float" -]; - -const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); - -function elmNameStyle(original: string, upper: boolean): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - upper ? firstUpperWordStyle : allLowerWordStyle, - firstUpperWordStyle, - upper ? allUpperWordStyle : allLowerWordStyle, - allUpperWordStyle, - "", - isLetterOrUnderscore - ); -} - -const upperNamingFunction = funPrefixNamer("upper", n => elmNameStyle(n, true)); -const lowerNamingFunction = funPrefixNamer("lower", n => elmNameStyle(n, false)); - -interface RequiredOrOptional { - fallback: string; - reqOrOpt: string; -} - -function requiredOrOptional(p: ClassProperty): RequiredOrOptional { - function optional(fallback: string): RequiredOrOptional { - return { reqOrOpt: "Jpipe.optional", fallback }; - } - - const t = p.type; - if (p.isOptional || (t instanceof UnionType && nullableFromUnion(t) !== null)) { - return optional(" Nothing"); - } - - if (t.kind === "null") { - return optional(" ()"); - } - - return { reqOrOpt: "Jpipe.required", fallback: "" }; -} +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type MultiWord, type Sourcelike, annotated, multiWord, parenIfNeeded, singleWord } from "../../Source"; +import { decapitalize, stringEscape } from "../../support/Strings"; +import { defined } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../../Type"; +import { matchType, nullableFromUnion } from "../../TypeUtils"; + +import { forbiddenNames } from "./constants"; +import { type elmOptions } from "./language"; +import { lowerNamingFunction, requiredOrOptional, upperNamingFunction } from "./utils"; interface TopLevelDependent { decoder?: Name; @@ -169,7 +39,7 @@ export class ElmRenderer extends ConvenienceRenderer { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return forbiddenNames; } @@ -690,12 +560,12 @@ import Dict exposing (Dict, map, toList)`); this.ensureBlankLine(); this.emitMultiline(`makeDictEncoder : (a -> Jenc.Value) -> Dict String a -> Jenc.Value makeDictEncoder f dict = - Jenc.object (toList (Dict.map (\\k -> f) dict)) + Jenc.object (toList (Dict.map (\\k -> f) dict)) makeNullableEncoder : (a -> Jenc.Value) -> Maybe a -> Jenc.Value makeNullableEncoder f m = - case m of - Just x -> f x - Nothing -> Jenc.null`); + case m of + Just x -> f x + Nothing -> Jenc.null`); } } diff --git a/packages/quicktype-core/src/language/Elm/constants.ts b/packages/quicktype-core/src/language/Elm/constants.ts new file mode 100644 index 000000000..e7a331f86 --- /dev/null +++ b/packages/quicktype-core/src/language/Elm/constants.ts @@ -0,0 +1,40 @@ +export const forbiddenNames = [ + "if", + "then", + "else", + "case", + "of", + "let", + "in", + "infix", + "type", + "module", + "where", + "import", + "exposing", + "as", + "port", + "int", + "float", + "bool", + "string", + "Jenc", + "Jdec", + "Jpipe", + "always", + "identity", + "Array", + "List", + "Dict", + "Maybe", + "map", + "toList", + "makeArrayEncoder", + "makeDictEncoder", + "makeNullableEncoder", + "Int", + "True", + "False", + "String", + "Float" +] as const; diff --git a/packages/quicktype-core/src/language/Elm/index.ts b/packages/quicktype-core/src/language/Elm/index.ts new file mode 100644 index 000000000..9dcf263d0 --- /dev/null +++ b/packages/quicktype-core/src/language/Elm/index.ts @@ -0,0 +1,2 @@ +export { ElmTargetLanguage, elmOptions } from "./language"; +export { ElmRenderer } from "./ElmRenderer"; diff --git a/packages/quicktype-core/src/language/Elm/language.ts b/packages/quicktype-core/src/language/Elm/language.ts new file mode 100644 index 000000000..6a193fbae --- /dev/null +++ b/packages/quicktype-core/src/language/Elm/language.ts @@ -0,0 +1,38 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { ElmRenderer } from "./ElmRenderer"; + +export const elmOptions = { + justTypes: new BooleanOption("just-types", "Plain types only", false), + useList: new EnumOption("array-type", "Use Array or List", [ + ["array", false], + ["list", true] + ]), + // FIXME: Do this via a configurable named eventually. + moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") +}; + +export class ElmTargetLanguage extends TargetLanguage { + public constructor() { + super("Elm", ["elm"], "elm"); + } + + protected getOptions(): Array> { + return [elmOptions.justTypes, elmOptions.moduleName, elmOptions.useList]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ElmRenderer { + return new ElmRenderer(this, renderContext, getOptionValues(elmOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/Elm/utils.ts b/packages/quicktype-core/src/language/Elm/utils.ts new file mode 100644 index 000000000..9f9ac2b82 --- /dev/null +++ b/packages/quicktype-core/src/language/Elm/utils.ts @@ -0,0 +1,52 @@ +import { UnionType, ClassProperty } from "../../Type"; +import { nullableFromUnion } from "../../TypeUtils"; +import { funPrefixNamer } from "../../Naming"; +import { + legalizeCharacters, + isLetterOrUnderscoreOrDigit, + isLetterOrUnderscore, + isAscii, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allLowerWordStyle, + allUpperWordStyle +} from "../../support/Strings"; + +const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); + +function elmNameStyle(original: string, upper: boolean): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + upper ? firstUpperWordStyle : allLowerWordStyle, + firstUpperWordStyle, + upper ? allUpperWordStyle : allLowerWordStyle, + allUpperWordStyle, + "", + isLetterOrUnderscore + ); +} + +export const upperNamingFunction = funPrefixNamer("upper", n => elmNameStyle(n, true)); +export const lowerNamingFunction = funPrefixNamer("lower", n => elmNameStyle(n, false)); + +type RequiredOrOptional = { + reqOrOpt: string; + fallback: string; +}; + +export function requiredOrOptional(p: ClassProperty): RequiredOrOptional { + function optional(fallback: string): RequiredOrOptional { + return { reqOrOpt: "Jpipe.optional", fallback }; + } + const t = p.type; + if (p.isOptional || (t instanceof UnionType && nullableFromUnion(t) !== null)) { + return optional(" Nothing"); + } + if (t.kind === "null") { + return optional(" ()"); + } + return { reqOrOpt: "Jpipe.required", fallback: "" }; +} From 59e2da22ed71cd809cf01df8d08fe518b29680cd Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:38:16 -0700 Subject: [PATCH 59/80] move Dart to own dir --- .../{Dart.ts => Dart/DartRenderer.ts} | 246 ++---------------- .../src/language/Dart/constants.ts | 71 +++++ .../quicktype-core/src/language/Dart/index.ts | 2 + .../src/language/Dart/language.ts | 70 +++++ .../quicktype-core/src/language/Dart/utils.ts | 61 +++++ 5 files changed, 227 insertions(+), 223 deletions(-) rename packages/quicktype-core/src/language/{Dart.ts => Dart/DartRenderer.ts} (80%) create mode 100644 packages/quicktype-core/src/language/Dart/constants.ts create mode 100644 packages/quicktype-core/src/language/Dart/index.ts create mode 100644 packages/quicktype-core/src/language/Dart/language.ts create mode 100644 packages/quicktype-core/src/language/Dart/utils.ts diff --git a/packages/quicktype-core/src/language/Dart.ts b/packages/quicktype-core/src/language/Dart/DartRenderer.ts similarity index 80% rename from packages/quicktype-core/src/language/Dart.ts rename to packages/quicktype-core/src/language/Dart/DartRenderer.ts index d8d471ec9..497e47cfb 100644 --- a/packages/quicktype-core/src/language/Dart.ts +++ b/packages/quicktype-core/src/language/Dart/DartRenderer.ts @@ -1,218 +1,18 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { DependencyName, type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; -import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - decapitalize, - escapeNonPrintableMapper, - firstUpperWordStyle, - isAscii, - isDigit, - isLetter, - isPrintable, - snakeCase, - splitIntoWords, - standardUnicodeHexEscape, - utf16ConcatMap, - utf16LegalizeCharacters -} from "../support/Strings"; -import { defined } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { - type ClassProperty, - type ClassType, - EnumType, - type PrimitiveStringTypeKind, - type TransformedStringTypeKind, - type Type, - type UnionType -} from "../Type"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../TypeUtils"; - -export const dartOptions = { - nullSafety: new BooleanOption("null-safety", "Null Safety", true), - justTypes: new BooleanOption("just-types", "Types only", false), - codersInClass: new BooleanOption("coders-in-class", "Put encoder & decoder in Class", false), - methodNamesWithMap: new BooleanOption("from-map", "Use method names fromMap() & toMap()", false, "secondary"), - requiredProperties: new BooleanOption("required-props", "Make all properties required", false), - finalProperties: new BooleanOption("final-props", "Make all properties final", false), - generateCopyWith: new BooleanOption("copy-with", "Generate CopyWith method", false), - useFreezed: new BooleanOption( - "use-freezed", - "Generate class definitions with @freezed compatibility", - false, - "secondary" - ), - useHive: new BooleanOption("use-hive", "Generate annotations for Hive type adapters", false, "secondary"), - useJsonAnnotation: new BooleanOption( - "use-json-annotation", - "Generate annotations for json_serializable", - false, - "secondary" - ), - partName: new StringOption("part-name", "Use this name in `part` directive", "NAME", "", "secondary") -}; - -export class DartTargetLanguage extends TargetLanguage { - public constructor() { - super("Dart", ["dart"], "dart"); - } - - protected getOptions(): Array> { - return [ - dartOptions.nullSafety, - dartOptions.justTypes, - dartOptions.codersInClass, - dartOptions.methodNamesWithMap, - dartOptions.requiredProperties, - dartOptions.finalProperties, - dartOptions.generateCopyWith, - dartOptions.useFreezed, - dartOptions.useHive, - dartOptions.useJsonAnnotation, - dartOptions.partName - ]; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - mapping.set("date", "date"); - mapping.set("date-time", "date-time"); - return mapping; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): DartRenderer { - const options = getOptionValues(dartOptions, untypedOptionValues); - return new DartRenderer(this, renderContext, options); - } -} - -const keywords = [ - "abstract", - "do", - "import", - "super", - "as", - "dynamic", - "in", - "switch", - "assert", - "else", - "interface", - "sync*", - "async", - "enum", - "is", - "this", - "async*", - "export", - "library", - "throw", - "await", - "external", - "mixin", - "true", - "break", - "extends", - "new", - "try", - "case", - "factory", - "null", - "typedef", - "catch", - "false", - "operator", - "var", - "class", - "final", - "part", - "void", - "const", - "finally", - "rethrow", - "while", - "continue", - "for", - "return", - "with", - "covariant", - "get", - "set", - "yield", - "default", - "if", - "static", - "yield*", - "deferred", - "implements", - "int", - "double", - "bool", - "Map", - "List", - "String", - "File", - "fromJson", - "toJson", - "fromMap", - "toMap" -]; - -const typeNamingFunction = funPrefixNamer("types", n => dartNameStyle(true, false, n)); -const propertyNamingFunction = funPrefixNamer("properties", n => dartNameStyle(false, false, n)); -const enumCaseNamingFunction = funPrefixNamer("enum-cases", n => dartNameStyle(true, true, n)); - -// Escape the dollar sign, which is used in string interpolation -const stringEscape = utf16ConcatMap( - escapeNonPrintableMapper(cp => isPrintable(cp) && cp !== 0x24, standardUnicodeHexEscape) -); - -function isStartCharacter(codePoint: number): boolean { - if (codePoint === 0x5f) return false; // underscore - return isAscii(codePoint) && isLetter(codePoint); -} - -function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); -} - -const legalizeName = utf16LegalizeCharacters(isPartCharacter); - -// FIXME: Handle acronyms consistently. In particular, that means that -// we have to use namers to produce the getter and setter names - we can't -// just capitalize and concatenate. -// https://stackoverflow.com/questions/8277355/naming-convention-for-upper-case-abbreviations -function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, original: string): string { - const words = splitIntoWords(original); - const firstWordStyle = upperUnderscore - ? allUpperWordStyle - : startWithUpper - ? firstUpperWordStyle - : allLowerWordStyle; - const restWordStyle = upperUnderscore ? allUpperWordStyle : firstUpperWordStyle; - return combineWords( - words, - legalizeName, - firstWordStyle, - restWordStyle, - firstWordStyle, - restWordStyle, - upperUnderscore ? "_" : "", - isStartCharacter - ); -} +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, type Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated, modifySource } from "../../Source"; +import { decapitalize, snakeCase, stringEscape } from "../../support/Strings"; +import { defined } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassProperty, type ClassType, EnumType, type Type, type UnionType } from "../../Type"; +import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { type dartOptions } from "./language"; +import { enumCaseNamingFunction, propertyNamingFunction, typeNamingFunction } from "./utils"; interface TopLevelDependents { decoder: Name; @@ -240,7 +40,7 @@ export class DartRenderer extends ConvenienceRenderer { super(targetLanguage, renderContext); } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return keywords; } @@ -879,15 +679,15 @@ export class DartRenderer extends ConvenienceRenderer { protected emitEnumValues(): void { this.ensureBlankLine(); this.emitMultiline(`class EnumValues { - Map map; - late Map reverseMap; + Map map; + late Map reverseMap; - EnumValues(this.map); + EnumValues(this.map); - Map get reverse { - reverseMap = map.map((k, v) => MapEntry(v, k)); - return reverseMap; - } + Map get reverse { + reverseMap = map.map((k, v) => MapEntry(v, k)); + return reverseMap; + } }`); } diff --git a/packages/quicktype-core/src/language/Dart/constants.ts b/packages/quicktype-core/src/language/Dart/constants.ts new file mode 100644 index 000000000..1251a6d8e --- /dev/null +++ b/packages/quicktype-core/src/language/Dart/constants.ts @@ -0,0 +1,71 @@ +export const keywords = [ + "abstract", + "do", + "import", + "super", + "as", + "dynamic", + "in", + "switch", + "assert", + "else", + "interface", + "sync*", + "async", + "enum", + "is", + "this", + "async*", + "export", + "library", + "throw", + "await", + "external", + "mixin", + "true", + "break", + "extends", + "new", + "try", + "case", + "factory", + "null", + "typedef", + "catch", + "false", + "operator", + "var", + "class", + "final", + "part", + "void", + "const", + "finally", + "rethrow", + "while", + "continue", + "for", + "return", + "with", + "covariant", + "get", + "set", + "yield", + "default", + "if", + "static", + "yield*", + "deferred", + "implements", + "int", + "double", + "bool", + "Map", + "List", + "String", + "File", + "fromJson", + "toJson", + "fromMap", + "toMap" +] as const; diff --git a/packages/quicktype-core/src/language/Dart/index.ts b/packages/quicktype-core/src/language/Dart/index.ts new file mode 100644 index 000000000..3820d5ad9 --- /dev/null +++ b/packages/quicktype-core/src/language/Dart/index.ts @@ -0,0 +1,2 @@ +export { DartTargetLanguage, dartOptions } from "./language"; +export { DartRenderer } from "./DartRenderer"; diff --git a/packages/quicktype-core/src/language/Dart/language.ts b/packages/quicktype-core/src/language/Dart/language.ts new file mode 100644 index 000000000..4598079f9 --- /dev/null +++ b/packages/quicktype-core/src/language/Dart/language.ts @@ -0,0 +1,70 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { DartRenderer } from "./DartRenderer"; + +export const dartOptions = { + nullSafety: new BooleanOption("null-safety", "Null Safety", true), + justTypes: new BooleanOption("just-types", "Types only", false), + codersInClass: new BooleanOption("coders-in-class", "Put encoder & decoder in Class", false), + methodNamesWithMap: new BooleanOption("from-map", "Use method names fromMap() & toMap()", false, "secondary"), + requiredProperties: new BooleanOption("required-props", "Make all properties required", false), + finalProperties: new BooleanOption("final-props", "Make all properties final", false), + generateCopyWith: new BooleanOption("copy-with", "Generate CopyWith method", false), + useFreezed: new BooleanOption( + "use-freezed", + "Generate class definitions with @freezed compatibility", + false, + "secondary" + ), + useHive: new BooleanOption("use-hive", "Generate annotations for Hive type adapters", false, "secondary"), + useJsonAnnotation: new BooleanOption( + "use-json-annotation", + "Generate annotations for json_serializable", + false, + "secondary" + ), + partName: new StringOption("part-name", "Use this name in `part` directive", "NAME", "", "secondary") +}; + +export class DartTargetLanguage extends TargetLanguage { + public constructor() { + super("Dart", ["dart"], "dart"); + } + + protected getOptions(): Array> { + return [ + dartOptions.nullSafety, + dartOptions.justTypes, + dartOptions.codersInClass, + dartOptions.methodNamesWithMap, + dartOptions.requiredProperties, + dartOptions.finalProperties, + dartOptions.generateCopyWith, + dartOptions.useFreezed, + dartOptions.useHive, + dartOptions.useJsonAnnotation, + dartOptions.partName + ]; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + mapping.set("date", "date"); + mapping.set("date-time", "date-time"); + return mapping; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): DartRenderer { + const options = getOptionValues(dartOptions, untypedOptionValues); + return new DartRenderer(this, renderContext, options); + } +} diff --git a/packages/quicktype-core/src/language/Dart/utils.ts b/packages/quicktype-core/src/language/Dart/utils.ts new file mode 100644 index 000000000..9f34d21f6 --- /dev/null +++ b/packages/quicktype-core/src/language/Dart/utils.ts @@ -0,0 +1,61 @@ +import { + allLowerWordStyle, + allUpperWordStyle, + combineWords, + escapeNonPrintableMapper, + firstUpperWordStyle, + isAscii, + isDigit, + isLetter, + isPrintable, + splitIntoWords, + standardUnicodeHexEscape, + utf16ConcatMap, + utf16LegalizeCharacters +} from "../../support/Strings"; + +import { funPrefixNamer } from "../../Naming"; + +export const typeNamingFunction = funPrefixNamer("types", n => dartNameStyle(true, false, n)); +export const propertyNamingFunction = funPrefixNamer("properties", n => dartNameStyle(false, false, n)); +export const enumCaseNamingFunction = funPrefixNamer("enum-cases", n => dartNameStyle(true, true, n)); + +// Escape the dollar sign, which is used in string interpolation +export const stringEscape = utf16ConcatMap( + escapeNonPrintableMapper(cp => isPrintable(cp) && cp !== 0x24, standardUnicodeHexEscape) +); + +function isStartCharacter(codePoint: number): boolean { + if (codePoint === 0x5f) return false; // underscore + return isAscii(codePoint) && isLetter(codePoint); +} + +function isPartCharacter(codePoint: number): boolean { + return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); +} + +const legalizeName = utf16LegalizeCharacters(isPartCharacter); + +// FIXME: Handle acronyms consistently. In particular, that means that +// we have to use namers to produce the getter and setter names - we can't +// just capitalize and concatenate. +// https://stackoverflow.com/questions/8277355/naming-convention-for-upper-case-abbreviations +export function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, original: string): string { + const words = splitIntoWords(original); + const firstWordStyle = upperUnderscore + ? allUpperWordStyle + : startWithUpper + ? firstUpperWordStyle + : allLowerWordStyle; + const restWordStyle = upperUnderscore ? allUpperWordStyle : firstUpperWordStyle; + return combineWords( + words, + legalizeName, + firstWordStyle, + restWordStyle, + firstWordStyle, + restWordStyle, + upperUnderscore ? "_" : "", + isStartCharacter + ); +} From a316b491cd80ea051e52f348593193b0e833a2b9 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:48:20 -0700 Subject: [PATCH 60/80] move CSharp to own dir --- .../quicktype-core/src/language/CSharp.ts | 2498 ----------------- .../src/language/CSharp/CSharpRenderer.ts | 383 +++ .../CSharp/NewtonSoftCSharpRenderer.ts | 802 ++++++ .../CSharp/SystemTextJsonCSharpRenderer.ts | 981 +++++++ .../src/language/CSharp/constants.ts | 79 + .../src/language/CSharp/index.ts | 4 + .../src/language/CSharp/language.ts | 181 ++ .../src/language/CSharp/utils.ts | 133 + 8 files changed, 2563 insertions(+), 2498 deletions(-) delete mode 100644 packages/quicktype-core/src/language/CSharp.ts create mode 100644 packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts create mode 100644 packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts create mode 100644 packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts create mode 100644 packages/quicktype-core/src/language/CSharp/constants.ts create mode 100644 packages/quicktype-core/src/language/CSharp/index.ts create mode 100644 packages/quicktype-core/src/language/CSharp/language.ts create mode 100644 packages/quicktype-core/src/language/CSharp/utils.ts diff --git a/packages/quicktype-core/src/language/CSharp.ts b/packages/quicktype-core/src/language/CSharp.ts deleted file mode 100644 index 331345d66..000000000 --- a/packages/quicktype-core/src/language/CSharp.ts +++ /dev/null @@ -1,2498 +0,0 @@ -import { arrayIntercalate } from "collection-utils"; -import unicode from "unicode-properties"; - -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { minMaxLengthForType, minMaxValueForType } from "../attributes/Constraints"; -import { ConvenienceRenderer, type ForbiddenWordsInfo, inferredNameOrder } from "../ConvenienceRenderer"; -import { DependencyName, type Name, type Namer, SimpleName, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { - BooleanOption, - EnumOption, - type Option, - type OptionValues, - StringOption, - getOptionValues -} from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated, modifySource } from "../Source"; -import { - type WordInName, - camelCase, - combineWords, - firstUpperWordStyle, - splitIntoWords, - utf16LegalizeCharacters, - utf16StringEscape -} from "../support/Strings"; -import { assert, assertNever, defined, panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { - ArrayDecodingTransformer, - ArrayEncodingTransformer, - ChoiceTransformer, - DecodingChoiceTransformer, - DecodingTransformer, - EncodingTransformer, - MinMaxLengthCheckTransformer, - MinMaxValueTransformer, - ParseStringTransformer, - StringMatchTransformer, - StringProducerTransformer, - StringifyTransformer, - type Transformation, - type Transformer, - UnionInstantiationTransformer, - UnionMemberMatchTransformer, - followTargetType, - transformationForType -} from "../Transformers"; -import { - ArrayType, - type ClassProperty, - ClassType, - EnumType, - type PrimitiveStringTypeKind, - type PrimitiveType, - type TransformedStringTypeKind, - type Type, - UnionType -} from "../Type"; -import { type StringTypeMapping } from "../TypeBuilder"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export enum Framework { - Newtonsoft = "Newtonsoft", - SystemTextJson = "SystemTextJson" -} - -export type Version = 5 | 6; -export interface OutputFeatures { - attributes: boolean; - helpers: boolean; -} - -export enum AccessModifier { - None = "None", - Public = "Public", - Internal = "Internal" -} - -export type CSharpTypeForAny = "object" | "dynamic"; - -function noFollow(t: Type): Type { - return t; -} - -function needTransformerForType(t: Type): "automatic" | "manual" | "nullable" | "none" { - if (t instanceof UnionType) { - const maybeNullable = nullableFromUnion(t); - if (maybeNullable === null) return "automatic"; - if (needTransformerForType(maybeNullable) === "manual") return "nullable"; - return "none"; - } - - if (t instanceof ArrayType) { - const itemsNeed = needTransformerForType(t.items); - if (itemsNeed === "manual" || itemsNeed === "nullable") return "automatic"; - return "none"; - } - - if (t instanceof EnumType) return "automatic"; - if (t.kind === "double") return minMaxValueForType(t) !== undefined ? "manual" : "none"; - if (t.kind === "integer-string" || t.kind === "bool-string") return "manual"; - if (t.kind === "string") { - return minMaxLengthForType(t) !== undefined ? "manual" : "none"; - } - - return "none"; -} - -function alwaysApplyTransformation(xf: Transformation): boolean { - const t = xf.targetType; - if (t instanceof EnumType) return true; - if (t instanceof UnionType) return nullableFromUnion(t) === null; - return false; -} - -/** - * The C# type for a given transformed string type. - */ -function csTypeForTransformedStringType(t: PrimitiveType): Sourcelike { - switch (t.kind) { - case "date-time": - return "DateTimeOffset"; - case "uuid": - return "Guid"; - case "uri": - return "Uri"; - default: - return panic(`Transformed string type ${t.kind} not supported`); - } -} - -export const cSharpOptions = { - framework: new EnumOption( - "framework", - "Serialization framework", - [ - ["NewtonSoft", Framework.Newtonsoft], - ["SystemTextJson", Framework.SystemTextJson] - ], - "NewtonSoft" - ), - useList: new EnumOption("array-type", "Use T[] or List", [ - ["array", false], - ["list", true] - ]), - dense: new EnumOption( - "density", - "Property density", - [ - ["normal", false], - ["dense", true] - ], - "normal", - "secondary" - ), - // FIXME: Do this via a configurable named eventually. - namespace: new StringOption("namespace", "Generated namespace", "NAME", "QuickType"), - version: new EnumOption( - "csharp-version", - "C# version", - [ - ["5", 5], - ["6", 6] - ], - "6", - "secondary" - ), - virtual: new BooleanOption("virtual", "Generate virtual properties", false), - typeForAny: new EnumOption( - "any-type", - 'Type to use for "any"', - [ - ["object", "object"], - ["dynamic", "dynamic"] - ], - "object", - "secondary" - ), - useDecimal: new EnumOption( - "number-type", - "Type to use for numbers", - [ - ["double", false], - ["decimal", true] - ], - "double", - "secondary" - ), - features: new EnumOption("features", "Output features", [ - ["complete", { namespaces: true, helpers: true, attributes: true }], - ["attributes-only", { namespaces: true, helpers: false, attributes: true }], - ["just-types-and-namespace", { namespaces: true, helpers: false, attributes: false }], - ["just-types", { namespaces: true, helpers: false, attributes: false }] - ]), - baseclass: new EnumOption( - "base-class", - "Base class", - [ - ["EntityData", "EntityData"], - ["Object", undefined] - ], - "Object", - "secondary" - ), - checkRequired: new BooleanOption("check-required", "Fail if required properties are missing", false), - keepPropertyName: new BooleanOption("keep-property-name", "Keep original field name generate", false) -}; - -export class CSharpTargetLanguage extends TargetLanguage { - public constructor() { - super("C#", ["cs", "csharp"], "cs"); - } - - protected getOptions(): Array> { - return [ - cSharpOptions.framework, - cSharpOptions.namespace, - cSharpOptions.version, - cSharpOptions.dense, - cSharpOptions.useList, - cSharpOptions.useDecimal, - cSharpOptions.typeForAny, - cSharpOptions.virtual, - cSharpOptions.features, - cSharpOptions.baseclass, - cSharpOptions.checkRequired, - cSharpOptions.keepPropertyName - ]; - } - - public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); - mapping.set("date", "date-time"); - mapping.set("time", "date-time"); - mapping.set("date-time", "date-time"); - mapping.set("uuid", "uuid"); - mapping.set("uri", "uri"); - mapping.set("integer-string", "integer-string"); - mapping.set("bool-string", "bool-string"); - return mapping; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - public needsTransformerForType(t: Type): boolean { - const need = needTransformerForType(t); - return need !== "none" && need !== "nullable"; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { - const options = getOptionValues(cSharpOptions, untypedOptionValues); - - switch (options.framework) { - case Framework.Newtonsoft: - return new NewtonsoftCSharpRenderer( - this, - renderContext, - getOptionValues(newtonsoftCSharpOptions, untypedOptionValues) - ); - case Framework.SystemTextJson: - return new SystemTextJsonCSharpRenderer( - this, - renderContext, - getOptionValues(systemTextJsonCSharpOptions, untypedOptionValues) - ); - default: - return assertNever(options.framework); - } - } -} - -const namingFunction = funPrefixNamer("namer", csNameStyle); -const namingFunctionKeep = funPrefixNamer("namerKeep", csNameStyleKeep); - -// FIXME: Make a Named? -const denseJsonPropertyName = "J"; -const denseRequiredEnumName = "R"; -const denseNullValueHandlingEnumName = "N"; - -function isStartCharacter(utf16Unit: number): boolean { - if (unicode.isAlphabetic(utf16Unit)) { - return true; - } - - return utf16Unit === 0x5f; // underscore -} - -function isPartCharacter(utf16Unit: number): boolean { - const category: string = unicode.getCategory(utf16Unit); - if (["Nd", "Pc", "Mn", "Mc"].includes(category)) { - return true; - } - - return isStartCharacter(utf16Unit); -} - -const legalizeName = utf16LegalizeCharacters(isPartCharacter); - -function csNameStyle(original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - firstUpperWordStyle, - firstUpperWordStyle, - firstUpperWordStyle, - firstUpperWordStyle, - "", - isStartCharacter - ); -} - -function csNameStyleKeep(original: string): string { - const keywords = [ - "abstract", - "as", - "base", - "bool", - "break", - "byte", - "case", - "catch", - "char", - "checked", - "class", - "const", - "continue", - "decimal", - "default", - "delegate", - "do", - "double", - "else", - "enum", - "event", - "explicit", - "extern", - "false", - "finally", - "fixed", - "float", - "for", - "foreach", - "goto", - "if", - "implicit", - "in", - "int", - "interface", - "internal", - "is", - "lock", - "long", - "namespace", - "new", - "null", - "object", - "operator", - "out", - "override", - "params", - "private", - "protected", - "public", - "readonly", - "ref", - "return", - "sbyte", - "sealed", - "short", - "sizeof", - "stackalloc", - "static", - "string", - "struct", - "switch", - "this", - "throw", - "true", - "try", - "typeof", - "uint", - "ulong", - "unchecked", - "unsafe", - "ushort", - "using", - "virtual", - "void", - "volatile", - "while" - ]; - - const words: WordInName[] = [ - { - word: original, - isAcronym: false - } - ]; - - const result = combineWords( - words, - legalizeName, - x => x, - x => x, - x => x, - x => x, - "", - isStartCharacter - ); - - return keywords.includes(result) ? "@" + result : result; -} - -function isValueType(t: Type): boolean { - if (t instanceof UnionType) { - return nullableFromUnion(t) === null; - } - - return ["integer", "double", "bool", "enum", "date-time", "uuid"].includes(t.kind); -} - -export class CSharpRenderer extends ConvenienceRenderer { - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - private readonly _csOptions: OptionValues - ) { - super(targetLanguage, renderContext); - } - - protected forbiddenNamesForGlobalNamespace(): string[] { - return ["QuickType", "Type", "System", "Console", "Exception", "DateTimeOffset", "Guid", "Uri"]; - } - - protected forbiddenForObjectProperties(_: ClassType, classNamed: Name): ForbiddenWordsInfo { - return { - names: [ - classNamed, - "ToString", - "GetHashCode", - "Finalize", - "Equals", - "GetType", - "MemberwiseClone", - "ReferenceEquals" - ], - includeGlobalForbidden: false - }; - } - - protected forbiddenForUnionMembers(_: UnionType, unionNamed: Name): ForbiddenWordsInfo { - return { names: [unionNamed], includeGlobalForbidden: true }; - } - - protected makeNamedTypeNamer(): Namer { - return namingFunction; - } - - protected namerForObjectProperty(): Namer { - return this._csOptions.keepPropertyName ? namingFunctionKeep : namingFunction; - } - - protected makeUnionMemberNamer(): Namer { - return namingFunction; - } - - protected makeEnumCaseNamer(): Namer { - return namingFunction; - } - - protected unionNeedsName(u: UnionType): boolean { - return nullableFromUnion(u) === null; - } - - protected namedTypeToNameForTopLevel(type: Type): Type | undefined { - // If the top-level type doesn't contain any classes or unions - // we have to define a class just for the `FromJson` method, in - // emitFromJsonForTopLevel. - return directlyReachableSingleNamedType(type); - } - - protected emitBlock(f: () => void, semicolon = false): void { - this.emitLine("{"); - this.indent(f); - this.emitLine("}", semicolon ? ";" : ""); - } - - protected get doubleType(): string { - return this._csOptions.useDecimal ? "decimal" : "double"; - } - - protected csType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { - const actualType = follow(t); - return matchType( - actualType, - _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, this._csOptions.typeForAny), - _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, this._csOptions.typeForAny), - _boolType => "bool", - _integerType => "long", - _doubleType => this.doubleType, - _stringType => "string", - arrayType => { - const itemsType = this.csType(arrayType.items, follow, withIssues); - if (this._csOptions.useList) { - return ["List<", itemsType, ">"]; - } else { - return [itemsType, "[]"]; - } - }, - classType => this.nameForNamedType(classType), - mapType => ["Dictionary"], - enumType => this.nameForNamedType(enumType), - unionType => { - const nullable = nullableFromUnion(unionType); - if (nullable !== null) return this.nullableCSType(nullable, noFollow); - return this.nameForNamedType(unionType); - }, - transformedStringType => csTypeForTransformedStringType(transformedStringType) - ); - } - - protected nullableCSType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { - t = followTargetType(t); - const csType = this.csType(t, follow, withIssues); - if (isValueType(t)) { - return [csType, "?"]; - } else { - return csType; - } - } - - protected baseclassForType(_t: Type): Sourcelike | undefined { - return undefined; - } - - protected emitType( - description: string[] | undefined, - accessModifier: AccessModifier, - declaration: Sourcelike, - name: Sourcelike, - baseclass: Sourcelike | undefined, - emitter: () => void - ): void { - switch (accessModifier) { - case AccessModifier.Public: - declaration = ["public ", declaration]; - break; - case AccessModifier.Internal: - declaration = ["internal ", declaration]; - break; - default: - break; - } - - this.emitDescription(description); - if (baseclass === undefined) { - this.emitLine(declaration, " ", name); - } else { - this.emitLine(declaration, " ", name, " : ", baseclass); - } - - this.emitBlock(emitter); - } - - protected attributesForProperty( - _property: ClassProperty, - _name: Name, - _c: ClassType, - _jsonName: string - ): Sourcelike[] | undefined { - return undefined; - } - - protected propertyDefinition(property: ClassProperty, name: Name, _c: ClassType, _jsonName: string): Sourcelike { - const t = property.type; - const csType = property.isOptional - ? this.nullableCSType(t, followTargetType, true) - : this.csType(t, followTargetType, true); - - const propertyArray = ["public "]; - - if (this._csOptions.virtual) propertyArray.push("virtual "); - - return [...propertyArray, csType, " ", name, " { get; set; }"]; - } - - protected emitDescriptionBlock(lines: Sourcelike[]): void { - const start = "/// "; - if (this._csOptions.dense) { - this.emitLine(start, lines.join("; "), ""); - } else { - this.emitCommentLines(lines, { lineStart: "/// ", beforeComment: start, afterComment: "/// " }); - } - } - - protected blankLinesBetweenAttributes(): boolean { - return false; - } - - private emitClassDefinition(c: ClassType, className: Name): void { - this.emitType( - this.descriptionForType(c), - AccessModifier.Public, - "partial class", - className, - this.baseclassForType(c), - () => { - if (c.getProperties().size === 0) return; - const blankLines = this.blankLinesBetweenAttributes() ? "interposing" : "none"; - let columns: Sourcelike[][] = []; - let isFirstProperty = true; - let previousDescription: string[] | undefined = undefined; - this.forEachClassProperty(c, blankLines, (name, jsonName, p) => { - const attributes = this.attributesForProperty(p, name, c, jsonName); - const description = this.descriptionForClassProperty(c, jsonName); - const property = this.propertyDefinition(p, name, c, jsonName); - if (attributes === undefined) { - if ( - // Descriptions should be preceded by an empty line - (!isFirstProperty && description !== undefined) || - // If the previous property has a description, leave an empty line - previousDescription !== undefined - ) { - this.ensureBlankLine(); - } - - this.emitDescription(description); - this.emitLine(property); - } else if (this._csOptions.dense && attributes.length > 0) { - const comment = description === undefined ? "" : ` // ${description.join("; ")}`; - columns.push([attributes, " ", property, comment]); - } else { - this.emitDescription(description); - for (const attribute of attributes) { - this.emitLine(attribute); - } - - this.emitLine(property); - } - - isFirstProperty = false; - previousDescription = description; - }); - if (columns.length > 0) { - this.emitTable(columns); - } - } - ); - } - - private emitUnionDefinition(u: UnionType, unionName: Name): void { - const nonNulls = removeNullFromUnion(u, true)[1]; - this.emitType( - this.descriptionForType(u), - AccessModifier.Public, - "partial struct", - unionName, - this.baseclassForType(u), - () => { - this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { - const csType = this.nullableCSType(t); - this.emitLine("public ", csType, " ", fieldName, ";"); - }); - this.ensureBlankLine(); - const nullTests: Sourcelike[] = Array.from(nonNulls).map(t => [ - this.nameForUnionMember(u, t), - " == null" - ]); - this.ensureBlankLine(); - this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { - const csType = this.csType(t); - this.emitExpressionMember( - ["public static implicit operator ", unionName, "(", csType, " ", fieldName, ")"], - ["new ", unionName, " { ", fieldName, " = ", fieldName, " }"] - ); - }); - if (u.findMember("null") === undefined) return; - this.emitExpressionMember("public bool IsNull", arrayIntercalate(" && ", nullTests), true); - } - ); - } - - private emitEnumDefinition(e: EnumType, enumName: Name): void { - const caseNames: Sourcelike[] = []; - this.forEachEnumCase(e, "none", name => { - if (caseNames.length > 0) caseNames.push(", "); - caseNames.push(name); - }); - this.emitDescription(this.descriptionForType(e)); - this.emitLine("public enum ", enumName, " { ", caseNames, " };"); - } - - protected emitExpressionMember(declare: Sourcelike, define: Sourcelike, isProperty = false): void { - if (this._csOptions.version === 5) { - this.emitLine(declare); - this.emitBlock(() => { - const stmt = ["return ", define, ";"]; - if (isProperty) { - this.emitLine("get"); - this.emitBlock(() => this.emitLine(stmt)); - } else { - this.emitLine(stmt); - } - }); - } else { - this.emitLine(declare, " => ", define, ";"); - } - } - - protected emitTypeSwitch( - types: Iterable, - condition: (t: T) => Sourcelike, - withBlock: boolean, - withReturn: boolean, - f: (t: T) => void - ): void { - assert(!withReturn || withBlock, "Can only have return with block"); - for (const t of types) { - this.emitLine("if (", condition(t), ")"); - if (withBlock) { - this.emitBlock(() => { - f(t); - if (withReturn) { - this.emitLine("return;"); - } - }); - } else { - this.indent(() => f(t)); - } - } - } - - protected emitUsing(ns: Sourcelike): void { - this.emitLine("using ", ns, ";"); - } - - protected emitUsings(): void { - for (const ns of ["System", "System.Collections.Generic"]) { - this.emitUsing(ns); - } - } - - protected emitRequiredHelpers(): void { - return; - } - - private emitTypesAndSupport(): void { - this.forEachObject("leading-and-interposing", (c: ClassType, name: Name) => this.emitClassDefinition(c, name)); - this.forEachEnum("leading-and-interposing", (e, name) => this.emitEnumDefinition(e, name)); - this.forEachUnion("leading-and-interposing", (u, name) => this.emitUnionDefinition(u, name)); - this.emitRequiredHelpers(); - } - - protected emitDefaultLeadingComments(): void { - return; - } - - protected emitDefaultFollowingComments(): void { - return; - } - - protected needNamespace(): boolean { - return true; - } - - protected emitSourceStructure(): void { - if (this.leadingComments !== undefined) { - this.emitComments(this.leadingComments); - } else { - this.emitDefaultLeadingComments(); - } - - this.ensureBlankLine(); - if (this.needNamespace()) { - this.emitLine("namespace ", this._csOptions.namespace); - this.emitBlock(() => { - this.emitUsings(); - this.emitTypesAndSupport(); - }); - } else { - this.emitUsings(); - this.emitTypesAndSupport(); - } - - this.emitDefaultFollowingComments(); - } -} - -export const newtonsoftCSharpOptions = Object.assign({}, cSharpOptions, {}); - -export class NewtonsoftCSharpRenderer extends CSharpRenderer { - private readonly _enumExtensionsNames = new Map(); - - private readonly _needHelpers: boolean; - - private readonly _needAttributes: boolean; - - private readonly _needNamespaces: boolean; - - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - private readonly _options: OptionValues - ) { - super(targetLanguage, renderContext, _options); - this._needHelpers = _options.features.helpers; - this._needAttributes = _options.features.attributes; - this._needNamespaces = _options.features.namespaces; - } - - protected forbiddenNamesForGlobalNamespace(): string[] { - const forbidden = [ - "Converter", - "JsonConverter", - "JsonSerializer", - "JsonWriter", - "JsonToken", - "Serialize", - "Newtonsoft", - "MetadataPropertyHandling", - "DateParseHandling", - "FromJson", - "Required" - ]; - if (this._options.dense) { - forbidden.push("J", "R", "N"); - } - - if (this._options.baseclass !== undefined) { - forbidden.push(this._options.baseclass); - } - - return super.forbiddenNamesForGlobalNamespace().concat(forbidden); - } - - protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { - const result = super.forbiddenForObjectProperties(c, className); - result.names = result.names.concat(["ToJson", "FromJson", "Required"]); - return result; - } - - protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { - if (typeName === undefined) { - let xfer = xf.transformer; - if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { - xfer = xfer.consumer; - } - - return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); - } - - return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); - } - - protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { - if (!(t instanceof EnumType)) return []; - - const extensionsName = new DependencyName( - namingFunction, - name.order + 30, - lookup => `${lookup(name)}_extensions` - ); - this._enumExtensionsNames.set(name, extensionsName); - return [extensionsName]; - } - - protected emitUsings(): void { - // FIXME: We need System.Collections.Generic whenever we have maps or use List. - if (!this._needAttributes && !this._needHelpers) return; - - super.emitUsings(); - this.ensureBlankLine(); - - for (const ns of ["System.Globalization", "Newtonsoft.Json", "Newtonsoft.Json.Converters"]) { - this.emitUsing(ns); - } - - if (this._options.dense) { - this.emitUsing([denseJsonPropertyName, " = Newtonsoft.Json.JsonPropertyAttribute"]); - this.emitUsing([denseRequiredEnumName, " = Newtonsoft.Json.Required"]); - this.emitUsing([denseNullValueHandlingEnumName, " = Newtonsoft.Json.NullValueHandling"]); - } - - if (this._options.baseclass === "EntityData") { - this.emitUsing("Microsoft.Azure.Mobile.Server"); - } - } - - protected baseclassForType(_t: Type): Sourcelike | undefined { - return this._options.baseclass; - } - - protected emitDefaultLeadingComments(): void { - if (!this._needHelpers) return; - - this.emitLine("// "); - this.emitLine("//"); - this.emitLine( - "// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do", - this.topLevels.size === 1 ? "" : " one of these", - ":" - ); - this.emitLine("//"); - this.emitLine("// using ", this._options.namespace, ";"); - this.emitLine("//"); - this.forEachTopLevel("none", (t, topLevelName) => { - let rhs: Sourcelike; - if (t instanceof EnumType) { - rhs = ["JsonConvert.DeserializeObject<", topLevelName, ">(jsonString)"]; - } else { - rhs = [topLevelName, ".FromJson(jsonString)"]; - } - - this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); - }); - } - - private converterForType(t: Type): Name | undefined { - let xf = transformationForType(t); - - if (xf === undefined && t instanceof UnionType) { - const maybeNullable = nullableFromUnion(t); - if (maybeNullable !== null) { - t = maybeNullable; - xf = transformationForType(t); - } - } - - if (xf === undefined) return undefined; - - if (alwaysApplyTransformation(xf)) return undefined; - - return defined(this.nameForTransformation(t)); - } - - protected attributesForProperty( - property: ClassProperty, - _name: Name, - _c: ClassType, - jsonName: string - ): Sourcelike[] | undefined { - if (!this._needAttributes) return undefined; - - const attributes: Sourcelike[] = []; - - const jsonProperty = this._options.dense ? denseJsonPropertyName : "JsonProperty"; - const escapedName = utf16StringEscape(jsonName); - const isNullable = followTargetType(property.type).isNullable; - const isOptional = property.isOptional; - const requiredClass = this._options.dense ? "R" : "Required"; - const nullValueHandlingClass = this._options.dense ? "N" : "NullValueHandling"; - const nullValueHandling = - isOptional && !isNullable ? [", NullValueHandling = ", nullValueHandlingClass, ".Ignore"] : []; - let required: Sourcelike; - if (!this._options.checkRequired || (isOptional && isNullable)) { - required = [nullValueHandling]; - } else if (isOptional && !isNullable) { - required = [", Required = ", requiredClass, ".DisallowNull", nullValueHandling]; - } else if (!isOptional && isNullable) { - required = [", Required = ", requiredClass, ".AllowNull"]; - } else { - required = [", Required = ", requiredClass, ".Always", nullValueHandling]; - } - - attributes.push(["[", jsonProperty, '("', escapedName, '"', required, ")]"]); - - const converter = this.converterForType(property.type); - if (converter !== undefined) { - attributes.push(["[JsonConverter(typeof(", converter, "))]"]); - } - - return attributes; - } - - protected blankLinesBetweenAttributes(): boolean { - return this._needAttributes && !this._options.dense; - } - - // The "this" type can't be `dynamic`, so we have to force it to `object`. - private topLevelResultType(t: Type): Sourcelike { - return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); - } - - private emitFromJsonForTopLevel(t: Type, name: Name): void { - if (t instanceof EnumType) return; - - let partial: string; - let typeKind: string; - const definedType = this.namedTypeToNameForTopLevel(t); - if (definedType !== undefined) { - partial = "partial "; - typeKind = definedType instanceof ClassType ? "class" : "struct"; - } else { - partial = ""; - typeKind = "class"; - } - - const csType = this.topLevelResultType(t); - this.emitType(undefined, AccessModifier.Public, [partial, typeKind], name, this.baseclassForType(t), () => { - // FIXME: Make FromJson a Named - this.emitExpressionMember( - ["public static ", csType, " FromJson(string json)"], - ["JsonConvert.DeserializeObject<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] - ); - }); - } - - private emitDecoderSwitch(emitBody: () => void): void { - this.emitLine("switch (reader.TokenType)"); - this.emitBlock(emitBody); - } - - private emitTokenCase(tokenType: string): void { - this.emitLine("case JsonToken.", tokenType, ":"); - } - - private emitThrow(message: Sourcelike): void { - this.emitLine("throw new Exception(", message, ");"); - } - - private deserializeTypeCode(typeName: Sourcelike): Sourcelike { - return ["serializer.Deserialize<", typeName, ">(reader)"]; - } - - private serializeValueCode(value: Sourcelike): Sourcelike { - return ["serializer.Serialize(writer, ", value, ")"]; - } - - private emitSerializeClass(): void { - // FIXME: Make Serialize a Named - this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { - // Sometimes multiple top-levels will resolve to the same type, so we have to take care - // not to emit more than one extension method for the same type. - const seenTypes = new Set(); - this.forEachTopLevel("none", t => { - // FIXME: Make ToJson a Named - if (!seenTypes.has(t)) { - seenTypes.add(t); - this.emitExpressionMember( - ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], - ["JsonConvert.SerializeObject(self, ", this._options.namespace, ".Converter.Settings)"] - ); - } - }); - }); - } - - private emitCanConvert(expr: Sourcelike): void { - this.emitExpressionMember("public override bool CanConvert(Type t)", expr); - } - - private emitReadJson(emitBody: () => void): void { - this.emitLine( - "public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)" - ); - this.emitBlock(emitBody); - } - - private emitWriteJson(variable: string, emitBody: () => void): void { - this.emitLine( - "public override void WriteJson(JsonWriter writer, object ", - variable, - ", JsonSerializer serializer)" - ); - this.emitBlock(emitBody); - } - - private converterObject(converterName: Name): Sourcelike { - // FIXME: Get a singleton - return [converterName, ".Singleton"]; - } - - private emitConverterClass(): void { - // FIXME: Make Converter a Named - const converterName: Sourcelike = ["Converter"]; - this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { - this.emitLine("public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings"); - this.emitBlock(() => { - this.emitLine("MetadataPropertyHandling = MetadataPropertyHandling.Ignore,"); - this.emitLine("DateParseHandling = DateParseHandling.None,"); - this.emitLine("Converters ="); - this.emitLine("{"); - this.indent(() => { - for (const [t, converter] of this.typesWithNamedTransformations) { - if (alwaysApplyTransformation(defined(transformationForType(t)))) { - this.emitLine(this.converterObject(converter), ","); - } - } - - this.emitLine("new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }"); - }); - this.emitLine("},"); - }, true); - }); - } - - private emitDecoderTransformerCase( - tokenCases: string[], - variableName: string, - xfer: Transformer | undefined, - targetType: Type, - emitFinish: (value: Sourcelike) => void - ): void { - if (xfer === undefined) return; - - for (const tokenCase of tokenCases) { - this.emitTokenCase(tokenCase); - } - - this.indent(() => { - const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); - if (!allHandled) { - this.emitLine("break;"); - } - }); - } - - private emitConsume( - value: Sourcelike, - consumer: Transformer | undefined, - targetType: Type, - emitFinish: (variableName: Sourcelike) => void - ): boolean { - if (consumer === undefined) { - emitFinish(value); - return true; - } else { - return this.emitTransformer(value, consumer, targetType, emitFinish); - } - } - - private emitDecodeTransformer( - xfer: Transformer, - targetType: Type, - emitFinish: (value: Sourcelike) => void, - variableName = "value" - ): boolean { - if (xfer instanceof DecodingTransformer) { - const source = xfer.sourceType; - const converter = this.converterForType(targetType); - if (converter !== undefined) { - const typeSource = this.csType(targetType); - this.emitLine("var converter = ", this.converterObject(converter), ";"); - this.emitLine( - "var ", - variableName, - " = (", - typeSource, - ")converter.ReadJson(reader, typeof(", - typeSource, - "), null, serializer);" - ); - } else if (source.kind !== "null") { - let output = targetType.kind === "double" ? targetType : source; - this.emitLine("var ", variableName, " = ", this.deserializeTypeCode(this.csType(output)), ";"); - } - - return this.emitConsume(variableName, xfer.consumer, targetType, emitFinish); - } else if (xfer instanceof ArrayDecodingTransformer) { - // FIXME: Consume StartArray - if (!(targetType instanceof ArrayType)) { - return panic("Array decoding must produce an array type"); - } - - // FIXME: handle EOF - this.emitLine("reader.Read();"); - this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); - this.emitLine("while (reader.TokenType != JsonToken.EndArray)"); - this.emitBlock(() => { - this.emitDecodeTransformer( - xfer.itemTransformer, - xfer.itemTargetType, - v => this.emitLine(variableName, ".Add(", v, ");"), - "arrayItem" - ); - // FIXME: handle EOF - this.emitLine("reader.Read();"); - }); - let result: Sourcelike = variableName; - if (!this._options.useList) { - result = [result, ".ToArray()"]; - } - - emitFinish(result); - return true; - } else if (xfer instanceof DecodingChoiceTransformer) { - this.emitDecoderSwitch(() => { - const nullTransformer = xfer.nullTransformer; - if (nullTransformer !== undefined) { - this.emitTokenCase("Null"); - this.indent(() => { - const allHandled = this.emitDecodeTransformer(nullTransformer, targetType, emitFinish, "null"); - if (!allHandled) { - this.emitLine("break"); - } - }); - } - - this.emitDecoderTransformerCase( - ["Integer"], - "integerValue", - xfer.integerTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - xfer.integerTransformer === undefined ? ["Integer", "Float"] : ["Float"], - "doubleValue", - xfer.doubleTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase(["Boolean"], "boolValue", xfer.boolTransformer, targetType, emitFinish); - this.emitDecoderTransformerCase( - ["String", "Date"], - "stringValue", - xfer.stringTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - ["StartObject"], - "objectValue", - xfer.objectTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - ["StartArray"], - "arrayValue", - xfer.arrayTransformer, - targetType, - emitFinish - ); - }); - return false; - } else { - return panic("Unknown transformer"); - } - } - - private stringCaseValue(t: Type, stringCase: string): Sourcelike { - if (t.kind === "string") { - return ['"', utf16StringEscape(stringCase), '"']; - } else if (t instanceof EnumType) { - return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; - } - - return panic(`Type ${t.kind} does not have string cases`); - } - - private emitTransformer( - variable: Sourcelike, - xfer: Transformer, - targetType: Type, - emitFinish: (value: Sourcelike) => void - ): boolean { - function directTargetType(continuation: Transformer | undefined): Type { - if (continuation === undefined) { - return targetType; - } - - return followTargetType(continuation.sourceType); - } - - if (xfer instanceof ChoiceTransformer) { - const caseXfers = xfer.transformers; - if (caseXfers.length > 1 && caseXfers.every(caseXfer => caseXfer instanceof StringMatchTransformer)) { - this.emitLine("switch (", variable, ")"); - this.emitBlock(() => { - for (const caseXfer of caseXfers) { - const matchXfer = caseXfer as StringMatchTransformer; - const value = this.stringCaseValue( - followTargetType(matchXfer.sourceType), - matchXfer.stringCase - ); - this.emitLine("case ", value, ":"); - this.indent(() => { - const allDone = this.emitTransformer( - variable, - matchXfer.transformer, - targetType, - emitFinish - ); - if (!allDone) { - this.emitLine("break;"); - } - }); - } - }); - // FIXME: Can we check for exhaustiveness? For enums it should be easy. - return false; - } else { - for (const caseXfer of caseXfers) { - this.emitTransformer(variable, caseXfer, targetType, emitFinish); - } - } - } else if (xfer instanceof UnionMemberMatchTransformer) { - const memberType = xfer.memberType; - const maybeNullable = nullableFromUnion(xfer.sourceType); - let test: Sourcelike; - let member: Sourcelike; - if (maybeNullable !== null) { - if (memberType.kind === "null") { - test = [variable, " == null"]; - member = "null"; - } else { - test = [variable, " != null"]; - member = variable; - } - } else if (memberType.kind === "null") { - test = [variable, ".IsNull"]; - member = "null"; - } else { - const memberName = this.nameForUnionMember(xfer.sourceType, memberType); - member = [variable, ".", memberName]; - test = [member, " != null"]; - } - - if (memberType.kind !== "null" && isValueType(memberType)) { - member = [member, ".Value"]; - } - - this.emitLine("if (", test, ")"); - this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); - } else if (xfer instanceof StringMatchTransformer) { - const value = this.stringCaseValue(followTargetType(xfer.sourceType), xfer.stringCase); - this.emitLine("if (", variable, " == ", value, ")"); - this.emitBlock(() => this.emitTransformer(variable, xfer.transformer, targetType, emitFinish)); - } else if (xfer instanceof EncodingTransformer) { - const converter = this.converterForType(xfer.sourceType); - if (converter !== undefined) { - this.emitLine("var converter = ", this.converterObject(converter), ";"); - this.emitLine("converter.WriteJson(writer, ", variable, ", serializer);"); - } else { - this.emitLine(this.serializeValueCode(variable), ";"); - } - - emitFinish([]); - return true; - } else if (xfer instanceof ArrayEncodingTransformer) { - this.emitLine("writer.WriteStartArray();"); - const itemVariable = "arrayItem"; - this.emitLine("foreach (var ", itemVariable, " in ", variable, ")"); - this.emitBlock(() => { - this.emitTransformer(itemVariable, xfer.itemTransformer, xfer.itemTargetType, () => { - return; - }); - }); - this.emitLine("writer.WriteEndArray();"); - emitFinish([]); - return true; - } else if (xfer instanceof ParseStringTransformer) { - const immediateTargetType = xfer.consumer === undefined ? targetType : xfer.consumer.sourceType; - switch (immediateTargetType.kind) { - case "date-time": - this.emitLine("DateTimeOffset dt;"); - this.emitLine("if (DateTimeOffset.TryParse(", variable, ", out dt))"); - this.emitBlock(() => this.emitConsume("dt", xfer.consumer, targetType, emitFinish)); - break; - case "uuid": - this.emitLine("Guid guid;"); - this.emitLine("if (Guid.TryParse(", variable, ", out guid))"); - this.emitBlock(() => this.emitConsume("guid", xfer.consumer, targetType, emitFinish)); - break; - case "uri": - this.emitLine("try"); - this.emitBlock(() => { - this.emitLine("var uri = new Uri(", variable, ");"); - this.emitConsume("uri", xfer.consumer, targetType, emitFinish); - }); - this.emitLine("catch (UriFormatException) {}"); - break; - case "integer": - this.emitLine("long l;"); - this.emitLine("if (Int64.TryParse(", variable, ", out l))"); - this.emitBlock(() => this.emitConsume("l", xfer.consumer, targetType, emitFinish)); - break; - case "bool": - this.emitLine("bool b;"); - this.emitLine("if (Boolean.TryParse(", variable, ", out b))"); - this.emitBlock(() => this.emitConsume("b", xfer.consumer, targetType, emitFinish)); - break; - default: - return panic(`Parsing string to ${immediateTargetType.kind} not supported`); - } - } else if (xfer instanceof StringifyTransformer) { - switch (xfer.sourceType.kind) { - case "date-time": - return this.emitConsume( - [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], - xfer.consumer, - targetType, - emitFinish - ); - case "uuid": - return this.emitConsume( - [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], - xfer.consumer, - targetType, - emitFinish - ); - case "integer": - case "uri": - return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); - case "bool": - this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); - return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); - default: - return panic(`Stringifying ${xfer.sourceType.kind} not supported`); - } - } else if (xfer instanceof StringProducerTransformer) { - const value = this.stringCaseValue(directTargetType(xfer.consumer), xfer.result); - return this.emitConsume(value, xfer.consumer, targetType, emitFinish); - } else if (xfer instanceof MinMaxLengthCheckTransformer) { - const min = xfer.minLength; - const max = xfer.maxLength; - const conditions: Sourcelike[] = []; - - if (min !== undefined) { - conditions.push([variable, ".Length >= ", min.toString()]); - } - - if (max !== undefined) { - conditions.push([variable, ".Length <= ", max.toString()]); - } - - this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); - return false; - } else if (xfer instanceof MinMaxValueTransformer) { - const min = xfer.minimum; - const max = xfer.maximum; - const conditions: Sourcelike[] = []; - - if (min !== undefined) { - conditions.push([variable, " >= ", min.toString()]); - } - - if (max !== undefined) { - conditions.push([variable, " <= ", max.toString()]); - } - - this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); - return false; - } else if (xfer instanceof UnionInstantiationTransformer) { - if (!(targetType instanceof UnionType)) { - return panic("Union instantiation transformer must produce a union type"); - } - - const maybeNullable = nullableFromUnion(targetType); - if (maybeNullable !== null) { - emitFinish(variable); - } else { - const unionName = this.nameForNamedType(targetType); - let initializer: Sourcelike; - if (xfer.sourceType.kind === "null") { - initializer = " "; - } else { - const memberName = this.nameForUnionMember(targetType, xfer.sourceType); - initializer = [" ", memberName, " = ", variable, " "]; - } - - emitFinish(["new ", unionName, " {", initializer, "}"]); - } - - return true; - } else { - return panic("Unknown transformer"); - } - - return false; - } - - private emitTransformation(converterName: Name, t: Type): void { - const xf = defined(transformationForType(t)); - const reverse = xf.reverse; - const targetType = xf.targetType; - const xfer = xf.transformer; - this.emitType(undefined, AccessModifier.Internal, "class", converterName, "JsonConverter", () => { - const csType = this.csType(targetType); - let canConvertExpr: Sourcelike = ["t == typeof(", csType, ")"]; - const haveNullable = isValueType(targetType); - if (haveNullable) { - canConvertExpr = [canConvertExpr, " || t == typeof(", csType, "?)"]; - } - - this.emitCanConvert(canConvertExpr); - this.ensureBlankLine(); - this.emitReadJson(() => { - // FIXME: It's unsatisfying that we need this. The reason is that we not - // only match T, but also T?. If we didn't, then the T in T? would not be - // deserialized with our converter but with the default one. Can we check - // whether the type is a nullable? - // FIXME: This could duplicate one of the cases handled below in - // `emitDecodeTransformer`. - if (haveNullable && !(targetType instanceof UnionType)) { - this.emitLine("if (reader.TokenType == JsonToken.Null) return null;"); - } - - const allHandled = this.emitDecodeTransformer(xfer, targetType, v => this.emitLine("return ", v, ";")); - if (!allHandled) { - this.emitThrow(['"Cannot unmarshal type ', csType, '"']); - } - }); - this.ensureBlankLine(); - this.emitWriteJson("untypedValue", () => { - // FIXME: See above. - if (haveNullable && !(targetType instanceof UnionType)) { - this.emitLine("if (untypedValue == null)"); - this.emitBlock(() => { - this.emitLine("serializer.Serialize(writer, null);"); - this.emitLine("return;"); - }); - } - - this.emitLine("var value = (", csType, ")untypedValue;"); - const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;") - ); - if (!allHandled) { - this.emitThrow(['"Cannot marshal type ', csType, '"']); - } - }); - this.ensureBlankLine(); - this.emitLine("public static readonly ", converterName, " Singleton = new ", converterName, "();"); - }); - } - - protected emitRequiredHelpers(): void { - if (this._needHelpers) { - this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); - this.ensureBlankLine(); - this.emitSerializeClass(); - } - - if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { - this.ensureBlankLine(); - this.emitConverterClass(); - this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); - } - } - - protected needNamespace(): boolean { - return this._needNamespaces; - } -} - -export const systemTextJsonCSharpOptions = Object.assign({}, cSharpOptions, {}); - -export class SystemTextJsonCSharpRenderer extends CSharpRenderer { - private readonly _enumExtensionsNames = new Map(); - - private readonly _needHelpers: boolean; - - private readonly _needAttributes: boolean; - - private readonly _needNamespaces: boolean; - - public constructor( - targetLanguage: TargetLanguage, - renderContext: RenderContext, - private readonly _options: OptionValues - ) { - super(targetLanguage, renderContext, _options); - this._needHelpers = _options.features.helpers; - this._needAttributes = _options.features.attributes; - this._needNamespaces = _options.features.namespaces; - } - - protected forbiddenNamesForGlobalNamespace(): string[] { - const forbidden = [ - "Converter", - "JsonConverter", - "JsonSerializer", - "JsonWriter", - "JsonToken", - "Serialize", - "JsonSerializerOptions", - // "Newtonsoft", - // "MetadataPropertyHandling", - // "DateParseHandling", - "FromJson", - "Required" - ]; - if (this._options.dense) { - forbidden.push("J", "R", "N"); - } - - if (this._options.baseclass !== undefined) { - forbidden.push(this._options.baseclass); - } - - return super.forbiddenNamesForGlobalNamespace().concat(forbidden); - } - - protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { - const result = super.forbiddenForObjectProperties(c, className); - result.names = result.names.concat(["ToJson", "FromJson", "Required"]); - return result; - } - - protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { - if (typeName === undefined) { - let xfer = xf.transformer; - if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { - xfer = xfer.consumer; - } - - return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); - } - - return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); - } - - protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { - if (!(t instanceof EnumType)) return []; - - const extensionsName = new DependencyName( - namingFunction, - name.order + 30, - lookup => `${lookup(name)}_extensions` - ); - this._enumExtensionsNames.set(name, extensionsName); - return [extensionsName]; - } - - protected emitUsings(): void { - // FIXME: We need System.Collections.Generic whenever we have maps or use List. - if (!this._needAttributes && !this._needHelpers) return; - - super.emitUsings(); - this.ensureBlankLine(); - - for (const ns of ["System.Text.Json", "System.Text.Json.Serialization", "System.Globalization"]) { - this.emitUsing(ns); - } - - if (this._options.dense) { - this.emitUsing([denseJsonPropertyName, " = System.Text.Json.Serialization.JsonPropertyNameAttribute"]); - // this.emitUsing([denseRequiredEnumName, " = Newtonsoft.Json.Required"]); - this.emitUsing([denseNullValueHandlingEnumName, " = System.Text.Json.Serialization.JsonIgnoreCondition"]); - } - - if (this._options.baseclass === "EntityData") { - this.emitUsing("Microsoft.Azure.Mobile.Server"); - } - } - - protected baseclassForType(_t: Type): Sourcelike | undefined { - return this._options.baseclass; - } - - protected emitDefaultFollowingComments(): void { - if (!this._needHelpers) return; - - this.emitLine("#pragma warning restore CS8618"); - this.emitLine("#pragma warning restore CS8601"); - this.emitLine("#pragma warning restore CS8603"); - } - - protected emitDefaultLeadingComments(): void { - if (!this._needHelpers) return; - - this.emitLine("// "); - this.emitLine("//"); - this.emitLine( - "// To parse this JSON data, add NuGet 'System.Text.Json' then do", - this.topLevels.size === 1 ? "" : " one of these", - ":" - ); - this.emitLine("//"); - this.emitLine("// using ", this._options.namespace, ";"); - this.emitLine("//"); - this.forEachTopLevel("none", (t, topLevelName) => { - let rhs: Sourcelike; - if (t instanceof EnumType) { - rhs = ["JsonSerializer.Deserialize<", topLevelName, ">(jsonString)"]; - } else { - rhs = [topLevelName, ".FromJson(jsonString)"]; - } - - this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); - }); - - // fix: should this be an option? Or respond to an existing option? - this.emitLine("#nullable enable"); - this.emitLine("#pragma warning disable CS8618"); - this.emitLine("#pragma warning disable CS8601"); - this.emitLine("#pragma warning disable CS8603"); - } - - private converterForType(t: Type): Name | undefined { - let xf = transformationForType(t); - - if (xf === undefined && t instanceof UnionType) { - const maybeNullable = nullableFromUnion(t); - if (maybeNullable !== null) { - t = maybeNullable; - xf = transformationForType(t); - } - } - - if (xf === undefined) return undefined; - - if (alwaysApplyTransformation(xf)) return undefined; - - return defined(this.nameForTransformation(t)); - } - - protected attributesForProperty( - property: ClassProperty, - _name: Name, - _c: ClassType, - jsonName: string - ): Sourcelike[] | undefined { - if (!this._needAttributes) return undefined; - - const attributes: Sourcelike[] = []; - - const jsonPropertyName = this._options.dense ? denseJsonPropertyName : "JsonPropertyName"; - const escapedName = utf16StringEscape(jsonName); - const isNullable = followTargetType(property.type).isNullable; - const isOptional = property.isOptional; - - if (isOptional && !isNullable) { - attributes.push(["[", "JsonIgnore", "(Condition = JsonIgnoreCondition.WhenWritingNull)]"]); - } - - // const requiredClass = this._options.dense ? "R" : "Required"; - // const nullValueHandlingClass = this._options.dense ? "N" : "NullValueHandling"; - // const nullValueHandling = isOptional && !isNullable ? [", NullValueHandling = ", nullValueHandlingClass, ".Ignore"] : []; - // let required: Sourcelike; - // if (!this._options.checkRequired || (isOptional && isNullable)) { - // required = [nullValueHandling]; - // } else if (isOptional && !isNullable) { - // required = [", Required = ", requiredClass, ".DisallowNull", nullValueHandling]; - // } else if (!isOptional && isNullable) { - // required = [", Required = ", requiredClass, ".AllowNull"]; - // } else { - // required = [", Required = ", requiredClass, ".Always", nullValueHandling]; - // } - - attributes.push(["[", jsonPropertyName, '("', escapedName, '")]']); - - const converter = this.converterForType(property.type); - if (converter !== undefined) { - attributes.push(["[JsonConverter(typeof(", converter, "))]"]); - } - - return attributes; - } - - protected blankLinesBetweenAttributes(): boolean { - return this._needAttributes && !this._options.dense; - } - - // The "this" type can't be `dynamic`, so we have to force it to `object`. - private topLevelResultType(t: Type): Sourcelike { - return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); - } - - private emitFromJsonForTopLevel(t: Type, name: Name): void { - if (t instanceof EnumType) return; - - let partial: string; - let typeKind: string; - const definedType = this.namedTypeToNameForTopLevel(t); - if (definedType !== undefined) { - partial = "partial "; - typeKind = definedType instanceof ClassType ? "class" : "struct"; - } else { - partial = ""; - typeKind = "class"; - } - - const csType = this.topLevelResultType(t); - this.emitType(undefined, AccessModifier.Public, [partial, typeKind], name, this.baseclassForType(t), () => { - // FIXME: Make FromJson a Named - this.emitExpressionMember( - ["public static ", csType, " FromJson(string json)"], - ["JsonSerializer.Deserialize<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] - ); - }); - } - - private emitDecoderSwitch(emitBody: () => void): void { - this.emitLine("switch (reader.TokenType)"); - this.emitBlock(emitBody); - } - - private emitTokenCase(tokenType: string): void { - this.emitLine("case JsonTokenType.", tokenType, ":"); - } - - private emitThrow(message: Sourcelike): void { - this.emitLine("throw new Exception(", message, ");"); - } - - private deserializeTypeCode(typeName: Sourcelike): Sourcelike { - switch (typeName) { - case "bool": - return ["reader.GetBoolean()"]; - case "long": - return ["reader.GetInt64()"]; - case "decimal": - return ["reader.GetDecimal()"]; - case "double": - return ["reader.GetDouble()"]; - case "string": - return ["reader.GetString()"]; - default: - return ["JsonSerializer.Deserialize<", typeName, ">(ref reader, options)"]; - } - } - - private serializeValueCode(value: Sourcelike): Sourcelike { - if (value !== "null") return ["JsonSerializer.Serialize(writer, ", value, ", options)"]; - else return ["writer.WriteNullValue()"]; - } - - private emitSerializeClass(): void { - // FIXME: Make Serialize a Named - this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { - // Sometimes multiple top-levels will resolve to the same type, so we have to take care - // not to emit more than one extension method for the same type. - const seenTypes = new Set(); - this.forEachTopLevel("none", t => { - // FIXME: Make ToJson a Named - if (!seenTypes.has(t)) { - seenTypes.add(t); - this.emitExpressionMember( - ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], - ["JsonSerializer.Serialize(self, ", this._options.namespace, ".Converter.Settings)"] - ); - } - }); - }); - } - - private emitCanConvert(expr: Sourcelike): void { - this.emitExpressionMember("public override bool CanConvert(Type t)", expr); - } - - private emitReadJson(emitBody: () => void, csType: Sourcelike): void { - this.emitLine( - "public override ", - csType, - " Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)" - ); - this.emitBlock(emitBody); - } - - private emitWriteJson(variable: string, emitBody: () => void, csType: Sourcelike): void { - this.emitLine( - "public override void Write(Utf8JsonWriter writer, ", - csType, - " ", - variable, - ", JsonSerializerOptions options)" - ); - this.emitBlock(emitBody); - } - - private converterObject(converterName: Name): Sourcelike { - // FIXME: Get a singleton - return [converterName, ".Singleton"]; - } - - private emitConverterClass(): void { - // FIXME: Make Converter a Named - const converterName: Sourcelike = ["Converter"]; - this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { - // Do not use .Web as defaults. That turns on caseInsensitive property names and will fail the keywords test. - this.emitLine( - "public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)" - ); - this.emitBlock(() => { - // this.emitLine("MetadataPropertyHandling = MetadataPropertyHandling.Ignore,"); - // this.emitLine("DateParseHandling = DateParseHandling.None,"); - this.emitLine("Converters ="); - this.emitLine("{"); - this.indent(() => { - for (const [t, converter] of this.typesWithNamedTransformations) { - if (alwaysApplyTransformation(defined(transformationForType(t)))) { - this.emitLine(this.converterObject(converter), ","); - } - } - - this.emitLine("new DateOnlyConverter(),"); - this.emitLine("new TimeOnlyConverter(),"); - this.emitLine("IsoDateTimeOffsetConverter.Singleton"); - // this.emitLine("new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }"); - }); - this.emitLine("},"); - }, true); - }); - } - - private emitDecoderTransformerCase( - tokenCases: string[], - variableName: string, - xfer: Transformer | undefined, - targetType: Type, - emitFinish: (value: Sourcelike) => void - ): void { - if (xfer === undefined) return; - - for (const tokenCase of tokenCases) { - this.emitTokenCase(tokenCase); - } - - this.indent(() => { - const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); - if (!allHandled) { - this.emitLine("break;"); - } - }); - } - - private emitConsume( - value: Sourcelike, - consumer: Transformer | undefined, - targetType: Type, - emitFinish: (variableName: Sourcelike) => void - ): boolean { - if (consumer === undefined) { - emitFinish(value); - return true; - } else { - return this.emitTransformer(value, consumer, targetType, emitFinish); - } - } - - private emitDecodeTransformer( - xfer: Transformer, - targetType: Type, - emitFinish: (value: Sourcelike) => void, - variableName = "value" - ): boolean { - if (xfer instanceof DecodingTransformer) { - const source = xfer.sourceType; - const converter = this.converterForType(targetType); - if (converter !== undefined) { - const typeSource = this.csType(targetType); - this.emitLine("var converter = ", this.converterObject(converter), ";"); - this.emitLine( - "var ", - variableName, - " = (", - typeSource, - ")converter.ReadJson(reader, typeof(", - typeSource, - "), null, serializer);" - ); - } else if (source.kind !== "null") { - let output = targetType.kind === "double" ? targetType : source; - this.emitLine("var ", variableName, " = ", this.deserializeTypeCode(this.csType(output)), ";"); - } - - return this.emitConsume(variableName, xfer.consumer, targetType, emitFinish); - } else if (xfer instanceof ArrayDecodingTransformer) { - // FIXME: Consume StartArray - if (!(targetType instanceof ArrayType)) { - return panic("Array decoding must produce an array type"); - } - - // FIXME: handle EOF - this.emitLine("reader.Read();"); - this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); - this.emitLine("while (reader.TokenType != JsonToken.EndArray)"); - this.emitBlock(() => { - this.emitDecodeTransformer( - xfer.itemTransformer, - xfer.itemTargetType, - v => this.emitLine(variableName, ".Add(", v, ");"), - "arrayItem" - ); - // FIXME: handle EOF - this.emitLine("reader.Read();"); - }); - let result: Sourcelike = variableName; - if (!this._options.useList) { - result = [result, ".ToArray()"]; - } - - emitFinish(result); - return true; - } else if (xfer instanceof DecodingChoiceTransformer) { - this.emitDecoderSwitch(() => { - const nullTransformer = xfer.nullTransformer; - if (nullTransformer !== undefined) { - this.emitTokenCase("Null"); - this.indent(() => { - const allHandled = this.emitDecodeTransformer(nullTransformer, targetType, emitFinish, "null"); - if (!allHandled) { - this.emitLine("break"); - } - }); - } - - this.emitDecoderTransformerCase( - ["Number"], - "integerValue", - xfer.integerTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - ["Number"], - // xfer.integerTransformer === undefined ? ["Integer", "Float"] : ["Float"], - "doubleValue", - xfer.doubleTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - ["True", "False"], - "boolValue", - xfer.boolTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - // ["String", "Date"], - ["String"], - "stringValue", - xfer.stringTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - ["StartObject"], - "objectValue", - xfer.objectTransformer, - targetType, - emitFinish - ); - this.emitDecoderTransformerCase( - ["StartArray"], - "arrayValue", - xfer.arrayTransformer, - targetType, - emitFinish - ); - }); - return false; - } else { - return panic("Unknown transformer"); - } - } - - private stringCaseValue(t: Type, stringCase: string): Sourcelike { - if (t.kind === "string") { - return ['"', utf16StringEscape(stringCase), '"']; - } else if (t instanceof EnumType) { - return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; - } - - return panic(`Type ${t.kind} does not have string cases`); - } - - private emitTransformer( - variable: Sourcelike, - xfer: Transformer, - targetType: Type, - emitFinish: (value: Sourcelike) => void - ): boolean { - function directTargetType(continuation: Transformer | undefined): Type { - if (continuation === undefined) { - return targetType; - } - - return followTargetType(continuation.sourceType); - } - - if (xfer instanceof ChoiceTransformer) { - const caseXfers = xfer.transformers; - if (caseXfers.length > 1 && caseXfers.every(caseXfer => caseXfer instanceof StringMatchTransformer)) { - this.emitLine("switch (", variable, ")"); - this.emitBlock(() => { - for (const caseXfer of caseXfers) { - const matchXfer = caseXfer as StringMatchTransformer; - const value = this.stringCaseValue( - followTargetType(matchXfer.sourceType), - matchXfer.stringCase - ); - this.emitLine("case ", value, ":"); - this.indent(() => { - const allDone = this.emitTransformer( - variable, - matchXfer.transformer, - targetType, - emitFinish - ); - if (!allDone) { - this.emitLine("break;"); - } - }); - } - }); - // FIXME: Can we check for exhaustiveness? For enums it should be easy. - return false; - } else { - for (const caseXfer of caseXfers) { - this.emitTransformer(variable, caseXfer, targetType, emitFinish); - } - } - } else if (xfer instanceof UnionMemberMatchTransformer) { - const memberType = xfer.memberType; - const maybeNullable = nullableFromUnion(xfer.sourceType); - let test: Sourcelike; - let member: Sourcelike; - if (maybeNullable !== null) { - if (memberType.kind === "null") { - test = [variable, " == null"]; - member = "null"; - } else { - test = [variable, " != null"]; - member = variable; - } - } else if (memberType.kind === "null") { - test = [variable, ".IsNull"]; - member = "null"; - } else { - const memberName = this.nameForUnionMember(xfer.sourceType, memberType); - member = [variable, ".", memberName]; - test = [member, " != null"]; - } - - if (memberType.kind !== "null" && isValueType(memberType)) { - member = [member, ".Value"]; - } - - this.emitLine("if (", test, ")"); - this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); - } else if (xfer instanceof StringMatchTransformer) { - const value = this.stringCaseValue(followTargetType(xfer.sourceType), xfer.stringCase); - this.emitLine("if (", variable, " == ", value, ")"); - this.emitBlock(() => this.emitTransformer(variable, xfer.transformer, targetType, emitFinish)); - } else if (xfer instanceof EncodingTransformer) { - const converter = this.converterForType(xfer.sourceType); - if (converter !== undefined) { - this.emitLine("var converter = ", this.converterObject(converter), ";"); - this.emitLine("converter.WriteJson(writer, ", variable, ", serializer);"); - } else { - this.emitLine(this.serializeValueCode(variable), ";"); - } - - emitFinish([]); - return true; - } else if (xfer instanceof ArrayEncodingTransformer) { - this.emitLine("writer.WriteStartArray();"); - const itemVariable = "arrayItem"; - this.emitLine("foreach (var ", itemVariable, " in ", variable, ")"); - this.emitBlock(() => { - this.emitTransformer(itemVariable, xfer.itemTransformer, xfer.itemTargetType, () => { - return; - }); - }); - this.emitLine("writer.WriteEndArray();"); - emitFinish([]); - return true; - } else if (xfer instanceof ParseStringTransformer) { - const immediateTargetType = xfer.consumer === undefined ? targetType : xfer.consumer.sourceType; - switch (immediateTargetType.kind) { - case "date-time": - this.emitLine("DateTimeOffset dt;"); - this.emitLine("if (DateTimeOffset.TryParse(", variable, ", out dt))"); - this.emitBlock(() => this.emitConsume("dt", xfer.consumer, targetType, emitFinish)); - break; - case "uuid": - this.emitLine("Guid guid;"); - this.emitLine("if (Guid.TryParse(", variable, ", out guid))"); - this.emitBlock(() => this.emitConsume("guid", xfer.consumer, targetType, emitFinish)); - break; - case "uri": - this.emitLine("try"); - this.emitBlock(() => { - // this.emitLine("var uri = new Uri(", variable, ");"); - // The default value about:blank should never happen, but this way we avoid a null reference warning. - this.emitLine('var uri = new Uri("about:blank");'); - this.emitLine("if (!string.IsNullOrEmpty(stringValue))"); - this.emitBlock(() => { - this.emitLine("uri = new Uri(", variable, ");"); - }); - this.emitConsume("uri", xfer.consumer, targetType, emitFinish); - }); - this.emitLine("catch (UriFormatException) {}"); - break; - case "integer": - this.emitLine("long l;"); - this.emitLine("if (Int64.TryParse(", variable, ", out l))"); - this.emitBlock(() => this.emitConsume("l", xfer.consumer, targetType, emitFinish)); - break; - case "bool": - this.emitLine("bool b;"); - this.emitLine("if (Boolean.TryParse(", variable, ", out b))"); - this.emitBlock(() => this.emitConsume("b", xfer.consumer, targetType, emitFinish)); - break; - default: - return panic(`Parsing string to ${immediateTargetType.kind} not supported`); - } - } else if (xfer instanceof StringifyTransformer) { - switch (xfer.sourceType.kind) { - case "date-time": - return this.emitConsume( - [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], - xfer.consumer, - targetType, - emitFinish - ); - case "uuid": - return this.emitConsume( - [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], - xfer.consumer, - targetType, - emitFinish - ); - case "integer": - case "uri": - return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); - case "bool": - this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); - return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); - default: - return panic(`Stringifying ${xfer.sourceType.kind} not supported`); - } - } else if (xfer instanceof StringProducerTransformer) { - const value = this.stringCaseValue(directTargetType(xfer.consumer), xfer.result); - return this.emitConsume(value, xfer.consumer, targetType, emitFinish); - } else if (xfer instanceof MinMaxLengthCheckTransformer) { - const min = xfer.minLength; - const max = xfer.maxLength; - const conditions: Sourcelike[] = []; - - if (min !== undefined) { - conditions.push([variable, ".Length >= ", min.toString()]); - } - - if (max !== undefined) { - conditions.push([variable, ".Length <= ", max.toString()]); - } - - this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); - return false; - } else if (xfer instanceof MinMaxValueTransformer) { - const min = xfer.minimum; - const max = xfer.maximum; - const conditions: Sourcelike[] = []; - - if (min !== undefined) { - conditions.push([variable, " >= ", min.toString()]); - } - - if (max !== undefined) { - conditions.push([variable, " <= ", max.toString()]); - } - - this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); - return false; - } else if (xfer instanceof UnionInstantiationTransformer) { - if (!(targetType instanceof UnionType)) { - return panic("Union instantiation transformer must produce a union type"); - } - - const maybeNullable = nullableFromUnion(targetType); - if (maybeNullable !== null) { - emitFinish(variable); - } else { - const unionName = this.nameForNamedType(targetType); - let initializer: Sourcelike; - if (xfer.sourceType.kind === "null") { - initializer = " "; - } else { - const memberName = this.nameForUnionMember(targetType, xfer.sourceType); - initializer = [" ", memberName, " = ", variable, " "]; - } - - emitFinish(["new ", unionName, " {", initializer, "}"]); - } - - return true; - } else { - return panic("Unknown transformer"); - } - - return false; - } - - private emitTransformation(converterName: Name, t: Type): void { - const xf = defined(transformationForType(t)); - const reverse = xf.reverse; - const targetType = xf.targetType; - const xfer = xf.transformer; - const csType = this.csType(targetType); - // const haveNullable = isValueType(targetType); - - // if (haveNullable) { - // converterName = ['Nullable', converterName]; - // csType = [csType, "?"]; - // } - this.emitType( - undefined, - AccessModifier.Internal, - "class", - converterName, - ["JsonConverter<", csType, ">"], - () => { - let canConvertExpr: Sourcelike = ["t == typeof(", csType, ")"]; - this.emitCanConvert(canConvertExpr); - this.ensureBlankLine(); - this.emitReadJson(() => { - // FIXME: It's unsatisfying that we need this. The reason is that we not - // only match T, but also T?. If we didn't, then the T in T? would not be - // deserialized with our converter but with the default one. Can we check - // whether the type is a nullable? - // FIXME: This could duplicate one of the cases handled below in - // `emitDecodeTransformer`. - // if (haveNullable && !(targetType instanceof UnionType)) { - // this.emitLine("if (reader.TokenType == JsonTokenType.Null) return null;"); - // } - - const allHandled = this.emitDecodeTransformer(xfer, targetType, v => - this.emitLine("return ", v, ";") - ); - if (!allHandled) { - this.emitThrow(['"Cannot unmarshal type ', csType, '"']); - } - }, csType); - this.ensureBlankLine(); - this.emitWriteJson( - "value", - () => { - // FIXME: See above. - // if (haveNullable && !(targetType instanceof UnionType)) { - // this.emitLine("if (value == null)"); - // this.emitBlock(() => { - // this.emitLine("writer.WriteNullValue();"); - // this.emitLine("return;"); - // }); - // } - - const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;") - ); - if (!allHandled) { - this.emitThrow(['"Cannot marshal type ', csType, '"']); - } - }, - csType - ); - this.ensureBlankLine(); - this.emitLine("public static readonly ", converterName, " Singleton = new ", converterName, "();"); - } - ); - } - - protected emitRequiredHelpers(): void { - if (this._needHelpers) { - this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); - this.ensureBlankLine(); - this.emitSerializeClass(); - } - - if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { - this.ensureBlankLine(); - this.emitConverterClass(); - this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); - this.emitMultiline(` -public class DateOnlyConverter : JsonConverter -{ - private readonly string serializationFormat; - public DateOnlyConverter() : this(null) { } - - public DateOnlyConverter(string? serializationFormat) - { - this.serializationFormat = serializationFormat ?? "yyyy-MM-dd"; - } - - public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var value = reader.GetString(); - return DateOnly.Parse(value!); - } - - public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) - => writer.WriteStringValue(value.ToString(serializationFormat)); -} - -public class TimeOnlyConverter : JsonConverter -{ - private readonly string serializationFormat; - - public TimeOnlyConverter() : this(null) { } - - public TimeOnlyConverter(string? serializationFormat) - { - this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff"; - } - - public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var value = reader.GetString(); - return TimeOnly.Parse(value!); - } - - public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options) - => writer.WriteStringValue(value.ToString(serializationFormat)); -} - -internal class IsoDateTimeOffsetConverter : JsonConverter -{ - public override bool CanConvert(Type t) => t == typeof(DateTimeOffset); - - private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; - - private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; - private string? _dateTimeFormat; - private CultureInfo? _culture; - - public DateTimeStyles DateTimeStyles - { - get => _dateTimeStyles; - set => _dateTimeStyles = value; - } - - public string? DateTimeFormat - { - get => _dateTimeFormat ?? string.Empty; - set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; - } - - public CultureInfo Culture - { - get => _culture ?? CultureInfo.CurrentCulture; - set => _culture = value; - } - - public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) - { - string text; - - - if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal - || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal) - { - value = value.ToUniversalTime(); - } - - text = value.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture); - - writer.WriteStringValue(text); - } - - public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - string? dateText = reader.GetString(); - - if (string.IsNullOrEmpty(dateText) == false) - { - if (!string.IsNullOrEmpty(_dateTimeFormat)) - { - return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); - } - else - { - return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles); - } - } - else - { - return default(DateTimeOffset); - } - } - - - public static readonly IsoDateTimeOffsetConverter Singleton = new IsoDateTimeOffsetConverter(); -}`); - } - } - - protected needNamespace(): boolean { - return this._needNamespaces; - } -} diff --git a/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts new file mode 100644 index 000000000..7b139b4af --- /dev/null +++ b/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts @@ -0,0 +1,383 @@ +import { arrayIntercalate } from "collection-utils"; + +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { assert } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { followTargetType } from "../../Transformers"; +import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../../Type"; +import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { AccessModifier, type cSharpOptions } from "./language"; +import { csTypeForTransformedStringType, isValueType, namingFunction, namingFunctionKeep, noFollow } from "./utils"; + +export class CSharpRenderer extends ConvenienceRenderer { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + private readonly _csOptions: OptionValues + ) { + super(targetLanguage, renderContext); + } + + protected forbiddenNamesForGlobalNamespace(): string[] { + return ["QuickType", "Type", "System", "Console", "Exception", "DateTimeOffset", "Guid", "Uri"]; + } + + protected forbiddenForObjectProperties(_: ClassType, classNamed: Name): ForbiddenWordsInfo { + return { + names: [ + classNamed, + "ToString", + "GetHashCode", + "Finalize", + "Equals", + "GetType", + "MemberwiseClone", + "ReferenceEquals" + ], + includeGlobalForbidden: false + }; + } + + protected forbiddenForUnionMembers(_: UnionType, unionNamed: Name): ForbiddenWordsInfo { + return { names: [unionNamed], includeGlobalForbidden: true }; + } + + protected makeNamedTypeNamer(): Namer { + return namingFunction; + } + + protected namerForObjectProperty(): Namer { + return this._csOptions.keepPropertyName ? namingFunctionKeep : namingFunction; + } + + protected makeUnionMemberNamer(): Namer { + return namingFunction; + } + + protected makeEnumCaseNamer(): Namer { + return namingFunction; + } + + protected unionNeedsName(u: UnionType): boolean { + return nullableFromUnion(u) === null; + } + + protected namedTypeToNameForTopLevel(type: Type): Type | undefined { + // If the top-level type doesn't contain any classes or unions + // we have to define a class just for the `FromJson` method, in + // emitFromJsonForTopLevel. + return directlyReachableSingleNamedType(type); + } + + protected emitBlock(f: () => void, semicolon = false): void { + this.emitLine("{"); + this.indent(f); + this.emitLine("}", semicolon ? ";" : ""); + } + + protected get doubleType(): string { + return this._csOptions.useDecimal ? "decimal" : "double"; + } + + protected csType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { + const actualType = follow(t); + return matchType( + actualType, + _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, this._csOptions.typeForAny), + _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, this._csOptions.typeForAny), + _boolType => "bool", + _integerType => "long", + _doubleType => this.doubleType, + _stringType => "string", + arrayType => { + const itemsType = this.csType(arrayType.items, follow, withIssues); + if (this._csOptions.useList) { + return ["List<", itemsType, ">"]; + } else { + return [itemsType, "[]"]; + } + }, + classType => this.nameForNamedType(classType), + mapType => ["Dictionary"], + enumType => this.nameForNamedType(enumType), + unionType => { + const nullable = nullableFromUnion(unionType); + if (nullable !== null) return this.nullableCSType(nullable, noFollow); + return this.nameForNamedType(unionType); + }, + transformedStringType => csTypeForTransformedStringType(transformedStringType) + ); + } + + protected nullableCSType(t: Type, follow: (t: Type) => Type = followTargetType, withIssues = false): Sourcelike { + t = followTargetType(t); + const csType = this.csType(t, follow, withIssues); + if (isValueType(t)) { + return [csType, "?"]; + } else { + return csType; + } + } + + protected baseclassForType(_t: Type): Sourcelike | undefined { + return undefined; + } + + protected emitType( + description: string[] | undefined, + accessModifier: AccessModifier, + declaration: Sourcelike, + name: Sourcelike, + baseclass: Sourcelike | undefined, + emitter: () => void + ): void { + switch (accessModifier) { + case AccessModifier.Public: + declaration = ["public ", declaration]; + break; + case AccessModifier.Internal: + declaration = ["internal ", declaration]; + break; + default: + break; + } + + this.emitDescription(description); + if (baseclass === undefined) { + this.emitLine(declaration, " ", name); + } else { + this.emitLine(declaration, " ", name, " : ", baseclass); + } + + this.emitBlock(emitter); + } + + protected attributesForProperty( + _property: ClassProperty, + _name: Name, + _c: ClassType, + _jsonName: string + ): Sourcelike[] | undefined { + return undefined; + } + + protected propertyDefinition(property: ClassProperty, name: Name, _c: ClassType, _jsonName: string): Sourcelike { + const t = property.type; + const csType = property.isOptional + ? this.nullableCSType(t, followTargetType, true) + : this.csType(t, followTargetType, true); + + const propertyArray = ["public "]; + + if (this._csOptions.virtual) propertyArray.push("virtual "); + + return [...propertyArray, csType, " ", name, " { get; set; }"]; + } + + protected emitDescriptionBlock(lines: Sourcelike[]): void { + const start = "/// "; + if (this._csOptions.dense) { + this.emitLine(start, lines.join("; "), ""); + } else { + this.emitCommentLines(lines, { lineStart: "/// ", beforeComment: start, afterComment: "/// " }); + } + } + + protected blankLinesBetweenAttributes(): boolean { + return false; + } + + private emitClassDefinition(c: ClassType, className: Name): void { + this.emitType( + this.descriptionForType(c), + AccessModifier.Public, + "partial class", + className, + this.baseclassForType(c), + () => { + if (c.getProperties().size === 0) return; + const blankLines = this.blankLinesBetweenAttributes() ? "interposing" : "none"; + let columns: Sourcelike[][] = []; + let isFirstProperty = true; + let previousDescription: string[] | undefined = undefined; + this.forEachClassProperty(c, blankLines, (name, jsonName, p) => { + const attributes = this.attributesForProperty(p, name, c, jsonName); + const description = this.descriptionForClassProperty(c, jsonName); + const property = this.propertyDefinition(p, name, c, jsonName); + if (attributes === undefined) { + if ( + // Descriptions should be preceded by an empty line + (!isFirstProperty && description !== undefined) || + // If the previous property has a description, leave an empty line + previousDescription !== undefined + ) { + this.ensureBlankLine(); + } + + this.emitDescription(description); + this.emitLine(property); + } else if (this._csOptions.dense && attributes.length > 0) { + const comment = description === undefined ? "" : ` // ${description.join("; ")}`; + columns.push([attributes, " ", property, comment]); + } else { + this.emitDescription(description); + for (const attribute of attributes) { + this.emitLine(attribute); + } + + this.emitLine(property); + } + + isFirstProperty = false; + previousDescription = description; + }); + if (columns.length > 0) { + this.emitTable(columns); + } + } + ); + } + + private emitUnionDefinition(u: UnionType, unionName: Name): void { + const nonNulls = removeNullFromUnion(u, true)[1]; + this.emitType( + this.descriptionForType(u), + AccessModifier.Public, + "partial struct", + unionName, + this.baseclassForType(u), + () => { + this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { + const csType = this.nullableCSType(t); + this.emitLine("public ", csType, " ", fieldName, ";"); + }); + this.ensureBlankLine(); + const nullTests: Sourcelike[] = Array.from(nonNulls).map(t => [ + this.nameForUnionMember(u, t), + " == null" + ]); + this.ensureBlankLine(); + this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { + const csType = this.csType(t); + this.emitExpressionMember( + ["public static implicit operator ", unionName, "(", csType, " ", fieldName, ")"], + ["new ", unionName, " { ", fieldName, " = ", fieldName, " }"] + ); + }); + if (u.findMember("null") === undefined) return; + this.emitExpressionMember("public bool IsNull", arrayIntercalate(" && ", nullTests), true); + } + ); + } + + private emitEnumDefinition(e: EnumType, enumName: Name): void { + const caseNames: Sourcelike[] = []; + this.forEachEnumCase(e, "none", name => { + if (caseNames.length > 0) caseNames.push(", "); + caseNames.push(name); + }); + this.emitDescription(this.descriptionForType(e)); + this.emitLine("public enum ", enumName, " { ", caseNames, " };"); + } + + protected emitExpressionMember(declare: Sourcelike, define: Sourcelike, isProperty = false): void { + if (this._csOptions.version === 5) { + this.emitLine(declare); + this.emitBlock(() => { + const stmt = ["return ", define, ";"]; + if (isProperty) { + this.emitLine("get"); + this.emitBlock(() => this.emitLine(stmt)); + } else { + this.emitLine(stmt); + } + }); + } else { + this.emitLine(declare, " => ", define, ";"); + } + } + + protected emitTypeSwitch( + types: Iterable, + condition: (t: T) => Sourcelike, + withBlock: boolean, + withReturn: boolean, + f: (t: T) => void + ): void { + assert(!withReturn || withBlock, "Can only have return with block"); + for (const t of types) { + this.emitLine("if (", condition(t), ")"); + if (withBlock) { + this.emitBlock(() => { + f(t); + if (withReturn) { + this.emitLine("return;"); + } + }); + } else { + this.indent(() => f(t)); + } + } + } + + protected emitUsing(ns: Sourcelike): void { + this.emitLine("using ", ns, ";"); + } + + protected emitUsings(): void { + for (const ns of ["System", "System.Collections.Generic"]) { + this.emitUsing(ns); + } + } + + protected emitRequiredHelpers(): void { + return; + } + + private emitTypesAndSupport(): void { + this.forEachObject("leading-and-interposing", (c: ClassType, name: Name) => this.emitClassDefinition(c, name)); + this.forEachEnum("leading-and-interposing", (e, name) => this.emitEnumDefinition(e, name)); + this.forEachUnion("leading-and-interposing", (u, name) => this.emitUnionDefinition(u, name)); + this.emitRequiredHelpers(); + } + + protected emitDefaultLeadingComments(): void { + return; + } + + protected emitDefaultFollowingComments(): void { + return; + } + + protected needNamespace(): boolean { + return true; + } + + protected emitSourceStructure(): void { + if (this.leadingComments !== undefined) { + this.emitComments(this.leadingComments); + } else { + this.emitDefaultLeadingComments(); + } + + this.ensureBlankLine(); + if (this.needNamespace()) { + this.emitLine("namespace ", this._csOptions.namespace); + this.emitBlock(() => { + this.emitUsings(); + this.emitTypesAndSupport(); + }); + } else { + this.emitUsings(); + this.emitTypesAndSupport(); + } + + this.emitDefaultFollowingComments(); + } +} diff --git a/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts new file mode 100644 index 000000000..f34c3053f --- /dev/null +++ b/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts @@ -0,0 +1,802 @@ +import { arrayIntercalate } from "collection-utils"; + +import { type ForbiddenWordsInfo, inferredNameOrder } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, SimpleName } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { camelCase, utf16StringEscape } from "../../support/Strings"; +import { defined, panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { + ArrayDecodingTransformer, + ArrayEncodingTransformer, + ChoiceTransformer, + DecodingChoiceTransformer, + DecodingTransformer, + EncodingTransformer, + MinMaxLengthCheckTransformer, + MinMaxValueTransformer, + ParseStringTransformer, + StringMatchTransformer, + StringProducerTransformer, + StringifyTransformer, + type Transformation, + type Transformer, + UnionInstantiationTransformer, + UnionMemberMatchTransformer, + followTargetType, + transformationForType +} from "../../Transformers"; +import { ArrayType, type ClassProperty, ClassType, EnumType, type Type, UnionType } from "../../Type"; +import { nullableFromUnion } from "../../TypeUtils"; + +import { CSharpRenderer } from "./CSharpRenderer"; +import { AccessModifier, type newtonsoftCSharpOptions } from "./language"; +import { + alwaysApplyTransformation, + denseJsonPropertyName, + denseNullValueHandlingEnumName, + denseRequiredEnumName, + isValueType, + namingFunction +} from "./utils"; + +export class NewtonsoftCSharpRenderer extends CSharpRenderer { + private readonly _enumExtensionsNames = new Map(); + + private readonly _needHelpers: boolean; + + private readonly _needAttributes: boolean; + + private readonly _needNamespaces: boolean; + + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + private readonly _options: OptionValues + ) { + super(targetLanguage, renderContext, _options); + this._needHelpers = _options.features.helpers; + this._needAttributes = _options.features.attributes; + this._needNamespaces = _options.features.namespaces; + } + + protected forbiddenNamesForGlobalNamespace(): string[] { + const forbidden = [ + "Converter", + "JsonConverter", + "JsonSerializer", + "JsonWriter", + "JsonToken", + "Serialize", + "Newtonsoft", + "MetadataPropertyHandling", + "DateParseHandling", + "FromJson", + "Required" + ]; + if (this._options.dense) { + forbidden.push("J", "R", "N"); + } + + if (this._options.baseclass !== undefined) { + forbidden.push(this._options.baseclass); + } + + return super.forbiddenNamesForGlobalNamespace().concat(forbidden); + } + + protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { + const result = super.forbiddenForObjectProperties(c, className); + result.names = result.names.concat(["ToJson", "FromJson", "Required"]); + return result; + } + + protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { + if (typeName === undefined) { + let xfer = xf.transformer; + if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { + xfer = xfer.consumer; + } + + return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); + } + + return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); + } + + protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { + if (!(t instanceof EnumType)) return []; + + const extensionsName = new DependencyName( + namingFunction, + name.order + 30, + lookup => `${lookup(name)}_extensions` + ); + this._enumExtensionsNames.set(name, extensionsName); + return [extensionsName]; + } + + protected emitUsings(): void { + // FIXME: We need System.Collections.Generic whenever we have maps or use List. + if (!this._needAttributes && !this._needHelpers) return; + + super.emitUsings(); + this.ensureBlankLine(); + + for (const ns of ["System.Globalization", "Newtonsoft.Json", "Newtonsoft.Json.Converters"]) { + this.emitUsing(ns); + } + + if (this._options.dense) { + this.emitUsing([denseJsonPropertyName, " = Newtonsoft.Json.JsonPropertyAttribute"]); + this.emitUsing([denseRequiredEnumName, " = Newtonsoft.Json.Required"]); + this.emitUsing([denseNullValueHandlingEnumName, " = Newtonsoft.Json.NullValueHandling"]); + } + + if (this._options.baseclass === "EntityData") { + this.emitUsing("Microsoft.Azure.Mobile.Server"); + } + } + + protected baseclassForType(_t: Type): Sourcelike | undefined { + return this._options.baseclass; + } + + protected emitDefaultLeadingComments(): void { + if (!this._needHelpers) return; + + this.emitLine("// "); + this.emitLine("//"); + this.emitLine( + "// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do", + this.topLevels.size === 1 ? "" : " one of these", + ":" + ); + this.emitLine("//"); + this.emitLine("// using ", this._options.namespace, ";"); + this.emitLine("//"); + this.forEachTopLevel("none", (t, topLevelName) => { + let rhs: Sourcelike; + if (t instanceof EnumType) { + rhs = ["JsonConvert.DeserializeObject<", topLevelName, ">(jsonString)"]; + } else { + rhs = [topLevelName, ".FromJson(jsonString)"]; + } + + this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); + }); + } + + private converterForType(t: Type): Name | undefined { + let xf = transformationForType(t); + + if (xf === undefined && t instanceof UnionType) { + const maybeNullable = nullableFromUnion(t); + if (maybeNullable !== null) { + t = maybeNullable; + xf = transformationForType(t); + } + } + + if (xf === undefined) return undefined; + + if (alwaysApplyTransformation(xf)) return undefined; + + return defined(this.nameForTransformation(t)); + } + + protected attributesForProperty( + property: ClassProperty, + _name: Name, + _c: ClassType, + jsonName: string + ): Sourcelike[] | undefined { + if (!this._needAttributes) return undefined; + + const attributes: Sourcelike[] = []; + + const jsonProperty = this._options.dense ? denseJsonPropertyName : "JsonProperty"; + const escapedName = utf16StringEscape(jsonName); + const isNullable = followTargetType(property.type).isNullable; + const isOptional = property.isOptional; + const requiredClass = this._options.dense ? "R" : "Required"; + const nullValueHandlingClass = this._options.dense ? "N" : "NullValueHandling"; + const nullValueHandling = + isOptional && !isNullable ? [", NullValueHandling = ", nullValueHandlingClass, ".Ignore"] : []; + let required: Sourcelike; + if (!this._options.checkRequired || (isOptional && isNullable)) { + required = [nullValueHandling]; + } else if (isOptional && !isNullable) { + required = [", Required = ", requiredClass, ".DisallowNull", nullValueHandling]; + } else if (!isOptional && isNullable) { + required = [", Required = ", requiredClass, ".AllowNull"]; + } else { + required = [", Required = ", requiredClass, ".Always", nullValueHandling]; + } + + attributes.push(["[", jsonProperty, '("', escapedName, '"', required, ")]"]); + + const converter = this.converterForType(property.type); + if (converter !== undefined) { + attributes.push(["[JsonConverter(typeof(", converter, "))]"]); + } + + return attributes; + } + + protected blankLinesBetweenAttributes(): boolean { + return this._needAttributes && !this._options.dense; + } + + // The "this" type can't be `dynamic`, so we have to force it to `object`. + private topLevelResultType(t: Type): Sourcelike { + return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); + } + + private emitFromJsonForTopLevel(t: Type, name: Name): void { + if (t instanceof EnumType) return; + + let partial: string; + let typeKind: string; + const definedType = this.namedTypeToNameForTopLevel(t); + if (definedType !== undefined) { + partial = "partial "; + typeKind = definedType instanceof ClassType ? "class" : "struct"; + } else { + partial = ""; + typeKind = "class"; + } + + const csType = this.topLevelResultType(t); + this.emitType(undefined, AccessModifier.Public, [partial, typeKind], name, this.baseclassForType(t), () => { + // FIXME: Make FromJson a Named + this.emitExpressionMember( + ["public static ", csType, " FromJson(string json)"], + ["JsonConvert.DeserializeObject<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] + ); + }); + } + + private emitDecoderSwitch(emitBody: () => void): void { + this.emitLine("switch (reader.TokenType)"); + this.emitBlock(emitBody); + } + + private emitTokenCase(tokenType: string): void { + this.emitLine("case JsonToken.", tokenType, ":"); + } + + private emitThrow(message: Sourcelike): void { + this.emitLine("throw new Exception(", message, ");"); + } + + private deserializeTypeCode(typeName: Sourcelike): Sourcelike { + return ["serializer.Deserialize<", typeName, ">(reader)"]; + } + + private serializeValueCode(value: Sourcelike): Sourcelike { + return ["serializer.Serialize(writer, ", value, ")"]; + } + + private emitSerializeClass(): void { + // FIXME: Make Serialize a Named + this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { + // Sometimes multiple top-levels will resolve to the same type, so we have to take care + // not to emit more than one extension method for the same type. + const seenTypes = new Set(); + this.forEachTopLevel("none", t => { + // FIXME: Make ToJson a Named + if (!seenTypes.has(t)) { + seenTypes.add(t); + this.emitExpressionMember( + ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], + ["JsonConvert.SerializeObject(self, ", this._options.namespace, ".Converter.Settings)"] + ); + } + }); + }); + } + + private emitCanConvert(expr: Sourcelike): void { + this.emitExpressionMember("public override bool CanConvert(Type t)", expr); + } + + private emitReadJson(emitBody: () => void): void { + this.emitLine( + "public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)" + ); + this.emitBlock(emitBody); + } + + private emitWriteJson(variable: string, emitBody: () => void): void { + this.emitLine( + "public override void WriteJson(JsonWriter writer, object ", + variable, + ", JsonSerializer serializer)" + ); + this.emitBlock(emitBody); + } + + private converterObject(converterName: Name): Sourcelike { + // FIXME: Get a singleton + return [converterName, ".Singleton"]; + } + + private emitConverterClass(): void { + // FIXME: Make Converter a Named + const converterName: Sourcelike = ["Converter"]; + this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { + this.emitLine("public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings"); + this.emitBlock(() => { + this.emitLine("MetadataPropertyHandling = MetadataPropertyHandling.Ignore,"); + this.emitLine("DateParseHandling = DateParseHandling.None,"); + this.emitLine("Converters ="); + this.emitLine("{"); + this.indent(() => { + for (const [t, converter] of this.typesWithNamedTransformations) { + if (alwaysApplyTransformation(defined(transformationForType(t)))) { + this.emitLine(this.converterObject(converter), ","); + } + } + + this.emitLine("new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }"); + }); + this.emitLine("},"); + }, true); + }); + } + + private emitDecoderTransformerCase( + tokenCases: string[], + variableName: string, + xfer: Transformer | undefined, + targetType: Type, + emitFinish: (value: Sourcelike) => void + ): void { + if (xfer === undefined) return; + + for (const tokenCase of tokenCases) { + this.emitTokenCase(tokenCase); + } + + this.indent(() => { + const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); + if (!allHandled) { + this.emitLine("break;"); + } + }); + } + + private emitConsume( + value: Sourcelike, + consumer: Transformer | undefined, + targetType: Type, + emitFinish: (variableName: Sourcelike) => void + ): boolean { + if (consumer === undefined) { + emitFinish(value); + return true; + } else { + return this.emitTransformer(value, consumer, targetType, emitFinish); + } + } + + private emitDecodeTransformer( + xfer: Transformer, + targetType: Type, + emitFinish: (value: Sourcelike) => void, + variableName = "value" + ): boolean { + if (xfer instanceof DecodingTransformer) { + const source = xfer.sourceType; + const converter = this.converterForType(targetType); + if (converter !== undefined) { + const typeSource = this.csType(targetType); + this.emitLine("var converter = ", this.converterObject(converter), ";"); + this.emitLine( + "var ", + variableName, + " = (", + typeSource, + ")converter.ReadJson(reader, typeof(", + typeSource, + "), null, serializer);" + ); + } else if (source.kind !== "null") { + let output = targetType.kind === "double" ? targetType : source; + this.emitLine("var ", variableName, " = ", this.deserializeTypeCode(this.csType(output)), ";"); + } + + return this.emitConsume(variableName, xfer.consumer, targetType, emitFinish); + } else if (xfer instanceof ArrayDecodingTransformer) { + // FIXME: Consume StartArray + if (!(targetType instanceof ArrayType)) { + return panic("Array decoding must produce an array type"); + } + + // FIXME: handle EOF + this.emitLine("reader.Read();"); + this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); + this.emitLine("while (reader.TokenType != JsonToken.EndArray)"); + this.emitBlock(() => { + this.emitDecodeTransformer( + xfer.itemTransformer, + xfer.itemTargetType, + v => this.emitLine(variableName, ".Add(", v, ");"), + "arrayItem" + ); + // FIXME: handle EOF + this.emitLine("reader.Read();"); + }); + let result: Sourcelike = variableName; + if (!this._options.useList) { + result = [result, ".ToArray()"]; + } + + emitFinish(result); + return true; + } else if (xfer instanceof DecodingChoiceTransformer) { + this.emitDecoderSwitch(() => { + const nullTransformer = xfer.nullTransformer; + if (nullTransformer !== undefined) { + this.emitTokenCase("Null"); + this.indent(() => { + const allHandled = this.emitDecodeTransformer(nullTransformer, targetType, emitFinish, "null"); + if (!allHandled) { + this.emitLine("break"); + } + }); + } + + this.emitDecoderTransformerCase( + ["Integer"], + "integerValue", + xfer.integerTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + xfer.integerTransformer === undefined ? ["Integer", "Float"] : ["Float"], + "doubleValue", + xfer.doubleTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase(["Boolean"], "boolValue", xfer.boolTransformer, targetType, emitFinish); + this.emitDecoderTransformerCase( + ["String", "Date"], + "stringValue", + xfer.stringTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + ["StartObject"], + "objectValue", + xfer.objectTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + ["StartArray"], + "arrayValue", + xfer.arrayTransformer, + targetType, + emitFinish + ); + }); + return false; + } else { + return panic("Unknown transformer"); + } + } + + private stringCaseValue(t: Type, stringCase: string): Sourcelike { + if (t.kind === "string") { + return ['"', utf16StringEscape(stringCase), '"']; + } else if (t instanceof EnumType) { + return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; + } + + return panic(`Type ${t.kind} does not have string cases`); + } + + private emitTransformer( + variable: Sourcelike, + xfer: Transformer, + targetType: Type, + emitFinish: (value: Sourcelike) => void + ): boolean { + function directTargetType(continuation: Transformer | undefined): Type { + if (continuation === undefined) { + return targetType; + } + + return followTargetType(continuation.sourceType); + } + + if (xfer instanceof ChoiceTransformer) { + const caseXfers = xfer.transformers; + if (caseXfers.length > 1 && caseXfers.every(caseXfer => caseXfer instanceof StringMatchTransformer)) { + this.emitLine("switch (", variable, ")"); + this.emitBlock(() => { + for (const caseXfer of caseXfers) { + const matchXfer = caseXfer as StringMatchTransformer; + const value = this.stringCaseValue( + followTargetType(matchXfer.sourceType), + matchXfer.stringCase + ); + this.emitLine("case ", value, ":"); + this.indent(() => { + const allDone = this.emitTransformer( + variable, + matchXfer.transformer, + targetType, + emitFinish + ); + if (!allDone) { + this.emitLine("break;"); + } + }); + } + }); + // FIXME: Can we check for exhaustiveness? For enums it should be easy. + return false; + } else { + for (const caseXfer of caseXfers) { + this.emitTransformer(variable, caseXfer, targetType, emitFinish); + } + } + } else if (xfer instanceof UnionMemberMatchTransformer) { + const memberType = xfer.memberType; + const maybeNullable = nullableFromUnion(xfer.sourceType); + let test: Sourcelike; + let member: Sourcelike; + if (maybeNullable !== null) { + if (memberType.kind === "null") { + test = [variable, " == null"]; + member = "null"; + } else { + test = [variable, " != null"]; + member = variable; + } + } else if (memberType.kind === "null") { + test = [variable, ".IsNull"]; + member = "null"; + } else { + const memberName = this.nameForUnionMember(xfer.sourceType, memberType); + member = [variable, ".", memberName]; + test = [member, " != null"]; + } + + if (memberType.kind !== "null" && isValueType(memberType)) { + member = [member, ".Value"]; + } + + this.emitLine("if (", test, ")"); + this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); + } else if (xfer instanceof StringMatchTransformer) { + const value = this.stringCaseValue(followTargetType(xfer.sourceType), xfer.stringCase); + this.emitLine("if (", variable, " == ", value, ")"); + this.emitBlock(() => this.emitTransformer(variable, xfer.transformer, targetType, emitFinish)); + } else if (xfer instanceof EncodingTransformer) { + const converter = this.converterForType(xfer.sourceType); + if (converter !== undefined) { + this.emitLine("var converter = ", this.converterObject(converter), ";"); + this.emitLine("converter.WriteJson(writer, ", variable, ", serializer);"); + } else { + this.emitLine(this.serializeValueCode(variable), ";"); + } + + emitFinish([]); + return true; + } else if (xfer instanceof ArrayEncodingTransformer) { + this.emitLine("writer.WriteStartArray();"); + const itemVariable = "arrayItem"; + this.emitLine("foreach (var ", itemVariable, " in ", variable, ")"); + this.emitBlock(() => { + this.emitTransformer(itemVariable, xfer.itemTransformer, xfer.itemTargetType, () => { + return; + }); + }); + this.emitLine("writer.WriteEndArray();"); + emitFinish([]); + return true; + } else if (xfer instanceof ParseStringTransformer) { + const immediateTargetType = xfer.consumer === undefined ? targetType : xfer.consumer.sourceType; + switch (immediateTargetType.kind) { + case "date-time": + this.emitLine("DateTimeOffset dt;"); + this.emitLine("if (DateTimeOffset.TryParse(", variable, ", out dt))"); + this.emitBlock(() => this.emitConsume("dt", xfer.consumer, targetType, emitFinish)); + break; + case "uuid": + this.emitLine("Guid guid;"); + this.emitLine("if (Guid.TryParse(", variable, ", out guid))"); + this.emitBlock(() => this.emitConsume("guid", xfer.consumer, targetType, emitFinish)); + break; + case "uri": + this.emitLine("try"); + this.emitBlock(() => { + this.emitLine("var uri = new Uri(", variable, ");"); + this.emitConsume("uri", xfer.consumer, targetType, emitFinish); + }); + this.emitLine("catch (UriFormatException) {}"); + break; + case "integer": + this.emitLine("long l;"); + this.emitLine("if (Int64.TryParse(", variable, ", out l))"); + this.emitBlock(() => this.emitConsume("l", xfer.consumer, targetType, emitFinish)); + break; + case "bool": + this.emitLine("bool b;"); + this.emitLine("if (Boolean.TryParse(", variable, ", out b))"); + this.emitBlock(() => this.emitConsume("b", xfer.consumer, targetType, emitFinish)); + break; + default: + return panic(`Parsing string to ${immediateTargetType.kind} not supported`); + } + } else if (xfer instanceof StringifyTransformer) { + switch (xfer.sourceType.kind) { + case "date-time": + return this.emitConsume( + [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], + xfer.consumer, + targetType, + emitFinish + ); + case "uuid": + return this.emitConsume( + [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], + xfer.consumer, + targetType, + emitFinish + ); + case "integer": + case "uri": + return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); + case "bool": + this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); + return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); + default: + return panic(`Stringifying ${xfer.sourceType.kind} not supported`); + } + } else if (xfer instanceof StringProducerTransformer) { + const value = this.stringCaseValue(directTargetType(xfer.consumer), xfer.result); + return this.emitConsume(value, xfer.consumer, targetType, emitFinish); + } else if (xfer instanceof MinMaxLengthCheckTransformer) { + const min = xfer.minLength; + const max = xfer.maxLength; + const conditions: Sourcelike[] = []; + + if (min !== undefined) { + conditions.push([variable, ".Length >= ", min.toString()]); + } + + if (max !== undefined) { + conditions.push([variable, ".Length <= ", max.toString()]); + } + + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); + this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + return false; + } else if (xfer instanceof MinMaxValueTransformer) { + const min = xfer.minimum; + const max = xfer.maximum; + const conditions: Sourcelike[] = []; + + if (min !== undefined) { + conditions.push([variable, " >= ", min.toString()]); + } + + if (max !== undefined) { + conditions.push([variable, " <= ", max.toString()]); + } + + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); + this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + return false; + } else if (xfer instanceof UnionInstantiationTransformer) { + if (!(targetType instanceof UnionType)) { + return panic("Union instantiation transformer must produce a union type"); + } + + const maybeNullable = nullableFromUnion(targetType); + if (maybeNullable !== null) { + emitFinish(variable); + } else { + const unionName = this.nameForNamedType(targetType); + let initializer: Sourcelike; + if (xfer.sourceType.kind === "null") { + initializer = " "; + } else { + const memberName = this.nameForUnionMember(targetType, xfer.sourceType); + initializer = [" ", memberName, " = ", variable, " "]; + } + + emitFinish(["new ", unionName, " {", initializer, "}"]); + } + + return true; + } else { + return panic("Unknown transformer"); + } + + return false; + } + + private emitTransformation(converterName: Name, t: Type): void { + const xf = defined(transformationForType(t)); + const reverse = xf.reverse; + const targetType = xf.targetType; + const xfer = xf.transformer; + this.emitType(undefined, AccessModifier.Internal, "class", converterName, "JsonConverter", () => { + const csType = this.csType(targetType); + let canConvertExpr: Sourcelike = ["t == typeof(", csType, ")"]; + const haveNullable = isValueType(targetType); + if (haveNullable) { + canConvertExpr = [canConvertExpr, " || t == typeof(", csType, "?)"]; + } + + this.emitCanConvert(canConvertExpr); + this.ensureBlankLine(); + this.emitReadJson(() => { + // FIXME: It's unsatisfying that we need this. The reason is that we not + // only match T, but also T?. If we didn't, then the T in T? would not be + // deserialized with our converter but with the default one. Can we check + // whether the type is a nullable? + // FIXME: This could duplicate one of the cases handled below in + // `emitDecodeTransformer`. + if (haveNullable && !(targetType instanceof UnionType)) { + this.emitLine("if (reader.TokenType == JsonToken.Null) return null;"); + } + + const allHandled = this.emitDecodeTransformer(xfer, targetType, v => this.emitLine("return ", v, ";")); + if (!allHandled) { + this.emitThrow(['"Cannot unmarshal type ', csType, '"']); + } + }); + this.ensureBlankLine(); + this.emitWriteJson("untypedValue", () => { + // FIXME: See above. + if (haveNullable && !(targetType instanceof UnionType)) { + this.emitLine("if (untypedValue == null)"); + this.emitBlock(() => { + this.emitLine("serializer.Serialize(writer, null);"); + this.emitLine("return;"); + }); + } + + this.emitLine("var value = (", csType, ")untypedValue;"); + const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => + this.emitLine("return;") + ); + if (!allHandled) { + this.emitThrow(['"Cannot marshal type ', csType, '"']); + } + }); + this.ensureBlankLine(); + this.emitLine("public static readonly ", converterName, " Singleton = new ", converterName, "();"); + }); + } + + protected emitRequiredHelpers(): void { + if (this._needHelpers) { + this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); + this.ensureBlankLine(); + this.emitSerializeClass(); + } + + if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { + this.ensureBlankLine(); + this.emitConverterClass(); + this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); + } + } + + protected needNamespace(): boolean { + return this._needNamespaces; + } +} diff --git a/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts new file mode 100644 index 000000000..7d9effc49 --- /dev/null +++ b/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts @@ -0,0 +1,981 @@ +import { arrayIntercalate } from "collection-utils"; + +import { type ForbiddenWordsInfo, inferredNameOrder } from "../../ConvenienceRenderer"; +import { DependencyName, type Name, SimpleName } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, modifySource } from "../../Source"; +import { camelCase, utf16StringEscape } from "../../support/Strings"; +import { defined, panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { + ArrayDecodingTransformer, + ArrayEncodingTransformer, + ChoiceTransformer, + DecodingChoiceTransformer, + DecodingTransformer, + EncodingTransformer, + MinMaxLengthCheckTransformer, + MinMaxValueTransformer, + ParseStringTransformer, + StringMatchTransformer, + StringProducerTransformer, + StringifyTransformer, + type Transformation, + type Transformer, + UnionInstantiationTransformer, + UnionMemberMatchTransformer, + followTargetType, + transformationForType +} from "../../Transformers"; +import { ArrayType, type ClassProperty, ClassType, EnumType, type Type, UnionType } from "../../Type"; +import { nullableFromUnion } from "../../TypeUtils"; + +import { CSharpRenderer } from "./CSharpRenderer"; +import { AccessModifier, type systemTextJsonCSharpOptions } from "./language"; +import { + alwaysApplyTransformation, + denseJsonPropertyName, + denseNullValueHandlingEnumName, + isValueType, + namingFunction +} from "./utils"; + +export class SystemTextJsonCSharpRenderer extends CSharpRenderer { + private readonly _enumExtensionsNames = new Map(); + + private readonly _needHelpers: boolean; + + private readonly _needAttributes: boolean; + + private readonly _needNamespaces: boolean; + + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + private readonly _options: OptionValues + ) { + super(targetLanguage, renderContext, _options); + this._needHelpers = _options.features.helpers; + this._needAttributes = _options.features.attributes; + this._needNamespaces = _options.features.namespaces; + } + + protected forbiddenNamesForGlobalNamespace(): string[] { + const forbidden = [ + "Converter", + "JsonConverter", + "JsonSerializer", + "JsonWriter", + "JsonToken", + "Serialize", + "JsonSerializerOptions", + // "Newtonsoft", + // "MetadataPropertyHandling", + // "DateParseHandling", + "FromJson", + "Required" + ]; + if (this._options.dense) { + forbidden.push("J", "R", "N"); + } + + if (this._options.baseclass !== undefined) { + forbidden.push(this._options.baseclass); + } + + return super.forbiddenNamesForGlobalNamespace().concat(forbidden); + } + + protected forbiddenForObjectProperties(c: ClassType, className: Name): ForbiddenWordsInfo { + const result = super.forbiddenForObjectProperties(c, className); + result.names = result.names.concat(["ToJson", "FromJson", "Required"]); + return result; + } + + protected makeNameForTransformation(xf: Transformation, typeName: Name | undefined): Name { + if (typeName === undefined) { + let xfer = xf.transformer; + if (xfer instanceof DecodingTransformer && xfer.consumer !== undefined) { + xfer = xfer.consumer; + } + + return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); + } + + return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); + } + + protected makeNamedTypeDependencyNames(t: Type, name: Name): DependencyName[] { + if (!(t instanceof EnumType)) return []; + + const extensionsName = new DependencyName( + namingFunction, + name.order + 30, + lookup => `${lookup(name)}_extensions` + ); + this._enumExtensionsNames.set(name, extensionsName); + return [extensionsName]; + } + + protected emitUsings(): void { + // FIXME: We need System.Collections.Generic whenever we have maps or use List. + if (!this._needAttributes && !this._needHelpers) return; + + super.emitUsings(); + this.ensureBlankLine(); + + for (const ns of ["System.Text.Json", "System.Text.Json.Serialization", "System.Globalization"]) { + this.emitUsing(ns); + } + + if (this._options.dense) { + this.emitUsing([denseJsonPropertyName, " = System.Text.Json.Serialization.JsonPropertyNameAttribute"]); + // this.emitUsing([denseRequiredEnumName, " = Newtonsoft.Json.Required"]); + this.emitUsing([denseNullValueHandlingEnumName, " = System.Text.Json.Serialization.JsonIgnoreCondition"]); + } + + if (this._options.baseclass === "EntityData") { + this.emitUsing("Microsoft.Azure.Mobile.Server"); + } + } + + protected baseclassForType(_t: Type): Sourcelike | undefined { + return this._options.baseclass; + } + + protected emitDefaultFollowingComments(): void { + if (!this._needHelpers) return; + + this.emitLine("#pragma warning restore CS8618"); + this.emitLine("#pragma warning restore CS8601"); + this.emitLine("#pragma warning restore CS8603"); + } + + protected emitDefaultLeadingComments(): void { + if (!this._needHelpers) return; + + this.emitLine("// "); + this.emitLine("//"); + this.emitLine( + "// To parse this JSON data, add NuGet 'System.Text.Json' then do", + this.topLevels.size === 1 ? "" : " one of these", + ":" + ); + this.emitLine("//"); + this.emitLine("// using ", this._options.namespace, ";"); + this.emitLine("//"); + this.forEachTopLevel("none", (t, topLevelName) => { + let rhs: Sourcelike; + if (t instanceof EnumType) { + rhs = ["JsonSerializer.Deserialize<", topLevelName, ">(jsonString)"]; + } else { + rhs = [topLevelName, ".FromJson(jsonString)"]; + } + + this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); + }); + + // fix: should this be an option? Or respond to an existing option? + this.emitLine("#nullable enable"); + this.emitLine("#pragma warning disable CS8618"); + this.emitLine("#pragma warning disable CS8601"); + this.emitLine("#pragma warning disable CS8603"); + } + + private converterForType(t: Type): Name | undefined { + let xf = transformationForType(t); + + if (xf === undefined && t instanceof UnionType) { + const maybeNullable = nullableFromUnion(t); + if (maybeNullable !== null) { + t = maybeNullable; + xf = transformationForType(t); + } + } + + if (xf === undefined) return undefined; + + if (alwaysApplyTransformation(xf)) return undefined; + + return defined(this.nameForTransformation(t)); + } + + protected attributesForProperty( + property: ClassProperty, + _name: Name, + _c: ClassType, + jsonName: string + ): Sourcelike[] | undefined { + if (!this._needAttributes) return undefined; + + const attributes: Sourcelike[] = []; + + const jsonPropertyName = this._options.dense ? denseJsonPropertyName : "JsonPropertyName"; + const escapedName = utf16StringEscape(jsonName); + const isNullable = followTargetType(property.type).isNullable; + const isOptional = property.isOptional; + + if (isOptional && !isNullable) { + attributes.push(["[", "JsonIgnore", "(Condition = JsonIgnoreCondition.WhenWritingNull)]"]); + } + + // const requiredClass = this._options.dense ? "R" : "Required"; + // const nullValueHandlingClass = this._options.dense ? "N" : "NullValueHandling"; + // const nullValueHandling = isOptional && !isNullable ? [", NullValueHandling = ", nullValueHandlingClass, ".Ignore"] : []; + // let required: Sourcelike; + // if (!this._options.checkRequired || (isOptional && isNullable)) { + // required = [nullValueHandling]; + // } else if (isOptional && !isNullable) { + // required = [", Required = ", requiredClass, ".DisallowNull", nullValueHandling]; + // } else if (!isOptional && isNullable) { + // required = [", Required = ", requiredClass, ".AllowNull"]; + // } else { + // required = [", Required = ", requiredClass, ".Always", nullValueHandling]; + // } + + attributes.push(["[", jsonPropertyName, '("', escapedName, '")]']); + + const converter = this.converterForType(property.type); + if (converter !== undefined) { + attributes.push(["[JsonConverter(typeof(", converter, "))]"]); + } + + return attributes; + } + + protected blankLinesBetweenAttributes(): boolean { + return this._needAttributes && !this._options.dense; + } + + // The "this" type can't be `dynamic`, so we have to force it to `object`. + private topLevelResultType(t: Type): Sourcelike { + return t.kind === "any" || t.kind === "none" ? "object" : this.csType(t); + } + + private emitFromJsonForTopLevel(t: Type, name: Name): void { + if (t instanceof EnumType) return; + + let partial: string; + let typeKind: string; + const definedType = this.namedTypeToNameForTopLevel(t); + if (definedType !== undefined) { + partial = "partial "; + typeKind = definedType instanceof ClassType ? "class" : "struct"; + } else { + partial = ""; + typeKind = "class"; + } + + const csType = this.topLevelResultType(t); + this.emitType(undefined, AccessModifier.Public, [partial, typeKind], name, this.baseclassForType(t), () => { + // FIXME: Make FromJson a Named + this.emitExpressionMember( + ["public static ", csType, " FromJson(string json)"], + ["JsonSerializer.Deserialize<", csType, ">(json, ", this._options.namespace, ".Converter.Settings)"] + ); + }); + } + + private emitDecoderSwitch(emitBody: () => void): void { + this.emitLine("switch (reader.TokenType)"); + this.emitBlock(emitBody); + } + + private emitTokenCase(tokenType: string): void { + this.emitLine("case JsonTokenType.", tokenType, ":"); + } + + private emitThrow(message: Sourcelike): void { + this.emitLine("throw new Exception(", message, ");"); + } + + private deserializeTypeCode(typeName: Sourcelike): Sourcelike { + switch (typeName) { + case "bool": + return ["reader.GetBoolean()"]; + case "long": + return ["reader.GetInt64()"]; + case "decimal": + return ["reader.GetDecimal()"]; + case "double": + return ["reader.GetDouble()"]; + case "string": + return ["reader.GetString()"]; + default: + return ["JsonSerializer.Deserialize<", typeName, ">(ref reader, options)"]; + } + } + + private serializeValueCode(value: Sourcelike): Sourcelike { + if (value !== "null") return ["JsonSerializer.Serialize(writer, ", value, ", options)"]; + else return ["writer.WriteNullValue()"]; + } + + private emitSerializeClass(): void { + // FIXME: Make Serialize a Named + this.emitType(undefined, AccessModifier.Public, "static class", "Serialize", undefined, () => { + // Sometimes multiple top-levels will resolve to the same type, so we have to take care + // not to emit more than one extension method for the same type. + const seenTypes = new Set(); + this.forEachTopLevel("none", t => { + // FIXME: Make ToJson a Named + if (!seenTypes.has(t)) { + seenTypes.add(t); + this.emitExpressionMember( + ["public static string ToJson(this ", this.topLevelResultType(t), " self)"], + ["JsonSerializer.Serialize(self, ", this._options.namespace, ".Converter.Settings)"] + ); + } + }); + }); + } + + private emitCanConvert(expr: Sourcelike): void { + this.emitExpressionMember("public override bool CanConvert(Type t)", expr); + } + + private emitReadJson(emitBody: () => void, csType: Sourcelike): void { + this.emitLine( + "public override ", + csType, + " Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)" + ); + this.emitBlock(emitBody); + } + + private emitWriteJson(variable: string, emitBody: () => void, csType: Sourcelike): void { + this.emitLine( + "public override void Write(Utf8JsonWriter writer, ", + csType, + " ", + variable, + ", JsonSerializerOptions options)" + ); + this.emitBlock(emitBody); + } + + private converterObject(converterName: Name): Sourcelike { + // FIXME: Get a singleton + return [converterName, ".Singleton"]; + } + + private emitConverterClass(): void { + // FIXME: Make Converter a Named + const converterName: Sourcelike = ["Converter"]; + this.emitType(undefined, AccessModifier.Internal, "static class", converterName, undefined, () => { + // Do not use .Web as defaults. That turns on caseInsensitive property names and will fail the keywords test. + this.emitLine( + "public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)" + ); + this.emitBlock(() => { + // this.emitLine("MetadataPropertyHandling = MetadataPropertyHandling.Ignore,"); + // this.emitLine("DateParseHandling = DateParseHandling.None,"); + this.emitLine("Converters ="); + this.emitLine("{"); + this.indent(() => { + for (const [t, converter] of this.typesWithNamedTransformations) { + if (alwaysApplyTransformation(defined(transformationForType(t)))) { + this.emitLine(this.converterObject(converter), ","); + } + } + + this.emitLine("new DateOnlyConverter(),"); + this.emitLine("new TimeOnlyConverter(),"); + this.emitLine("IsoDateTimeOffsetConverter.Singleton"); + // this.emitLine("new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }"); + }); + this.emitLine("},"); + }, true); + }); + } + + private emitDecoderTransformerCase( + tokenCases: string[], + variableName: string, + xfer: Transformer | undefined, + targetType: Type, + emitFinish: (value: Sourcelike) => void + ): void { + if (xfer === undefined) return; + + for (const tokenCase of tokenCases) { + this.emitTokenCase(tokenCase); + } + + this.indent(() => { + const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); + if (!allHandled) { + this.emitLine("break;"); + } + }); + } + + private emitConsume( + value: Sourcelike, + consumer: Transformer | undefined, + targetType: Type, + emitFinish: (variableName: Sourcelike) => void + ): boolean { + if (consumer === undefined) { + emitFinish(value); + return true; + } else { + return this.emitTransformer(value, consumer, targetType, emitFinish); + } + } + + private emitDecodeTransformer( + xfer: Transformer, + targetType: Type, + emitFinish: (value: Sourcelike) => void, + variableName = "value" + ): boolean { + if (xfer instanceof DecodingTransformer) { + const source = xfer.sourceType; + const converter = this.converterForType(targetType); + if (converter !== undefined) { + const typeSource = this.csType(targetType); + this.emitLine("var converter = ", this.converterObject(converter), ";"); + this.emitLine( + "var ", + variableName, + " = (", + typeSource, + ")converter.ReadJson(reader, typeof(", + typeSource, + "), null, serializer);" + ); + } else if (source.kind !== "null") { + let output = targetType.kind === "double" ? targetType : source; + this.emitLine("var ", variableName, " = ", this.deserializeTypeCode(this.csType(output)), ";"); + } + + return this.emitConsume(variableName, xfer.consumer, targetType, emitFinish); + } else if (xfer instanceof ArrayDecodingTransformer) { + // FIXME: Consume StartArray + if (!(targetType instanceof ArrayType)) { + return panic("Array decoding must produce an array type"); + } + + // FIXME: handle EOF + this.emitLine("reader.Read();"); + this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); + this.emitLine("while (reader.TokenType != JsonToken.EndArray)"); + this.emitBlock(() => { + this.emitDecodeTransformer( + xfer.itemTransformer, + xfer.itemTargetType, + v => this.emitLine(variableName, ".Add(", v, ");"), + "arrayItem" + ); + // FIXME: handle EOF + this.emitLine("reader.Read();"); + }); + let result: Sourcelike = variableName; + if (!this._options.useList) { + result = [result, ".ToArray()"]; + } + + emitFinish(result); + return true; + } else if (xfer instanceof DecodingChoiceTransformer) { + this.emitDecoderSwitch(() => { + const nullTransformer = xfer.nullTransformer; + if (nullTransformer !== undefined) { + this.emitTokenCase("Null"); + this.indent(() => { + const allHandled = this.emitDecodeTransformer(nullTransformer, targetType, emitFinish, "null"); + if (!allHandled) { + this.emitLine("break"); + } + }); + } + + this.emitDecoderTransformerCase( + ["Number"], + "integerValue", + xfer.integerTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + ["Number"], + // xfer.integerTransformer === undefined ? ["Integer", "Float"] : ["Float"], + "doubleValue", + xfer.doubleTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + ["True", "False"], + "boolValue", + xfer.boolTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + // ["String", "Date"], + ["String"], + "stringValue", + xfer.stringTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + ["StartObject"], + "objectValue", + xfer.objectTransformer, + targetType, + emitFinish + ); + this.emitDecoderTransformerCase( + ["StartArray"], + "arrayValue", + xfer.arrayTransformer, + targetType, + emitFinish + ); + }); + return false; + } else { + return panic("Unknown transformer"); + } + } + + private stringCaseValue(t: Type, stringCase: string): Sourcelike { + if (t.kind === "string") { + return ['"', utf16StringEscape(stringCase), '"']; + } else if (t instanceof EnumType) { + return [this.nameForNamedType(t), ".", this.nameForEnumCase(t, stringCase)]; + } + + return panic(`Type ${t.kind} does not have string cases`); + } + + private emitTransformer( + variable: Sourcelike, + xfer: Transformer, + targetType: Type, + emitFinish: (value: Sourcelike) => void + ): boolean { + function directTargetType(continuation: Transformer | undefined): Type { + if (continuation === undefined) { + return targetType; + } + + return followTargetType(continuation.sourceType); + } + + if (xfer instanceof ChoiceTransformer) { + const caseXfers = xfer.transformers; + if (caseXfers.length > 1 && caseXfers.every(caseXfer => caseXfer instanceof StringMatchTransformer)) { + this.emitLine("switch (", variable, ")"); + this.emitBlock(() => { + for (const caseXfer of caseXfers) { + const matchXfer = caseXfer as StringMatchTransformer; + const value = this.stringCaseValue( + followTargetType(matchXfer.sourceType), + matchXfer.stringCase + ); + this.emitLine("case ", value, ":"); + this.indent(() => { + const allDone = this.emitTransformer( + variable, + matchXfer.transformer, + targetType, + emitFinish + ); + if (!allDone) { + this.emitLine("break;"); + } + }); + } + }); + // FIXME: Can we check for exhaustiveness? For enums it should be easy. + return false; + } else { + for (const caseXfer of caseXfers) { + this.emitTransformer(variable, caseXfer, targetType, emitFinish); + } + } + } else if (xfer instanceof UnionMemberMatchTransformer) { + const memberType = xfer.memberType; + const maybeNullable = nullableFromUnion(xfer.sourceType); + let test: Sourcelike; + let member: Sourcelike; + if (maybeNullable !== null) { + if (memberType.kind === "null") { + test = [variable, " == null"]; + member = "null"; + } else { + test = [variable, " != null"]; + member = variable; + } + } else if (memberType.kind === "null") { + test = [variable, ".IsNull"]; + member = "null"; + } else { + const memberName = this.nameForUnionMember(xfer.sourceType, memberType); + member = [variable, ".", memberName]; + test = [member, " != null"]; + } + + if (memberType.kind !== "null" && isValueType(memberType)) { + member = [member, ".Value"]; + } + + this.emitLine("if (", test, ")"); + this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); + } else if (xfer instanceof StringMatchTransformer) { + const value = this.stringCaseValue(followTargetType(xfer.sourceType), xfer.stringCase); + this.emitLine("if (", variable, " == ", value, ")"); + this.emitBlock(() => this.emitTransformer(variable, xfer.transformer, targetType, emitFinish)); + } else if (xfer instanceof EncodingTransformer) { + const converter = this.converterForType(xfer.sourceType); + if (converter !== undefined) { + this.emitLine("var converter = ", this.converterObject(converter), ";"); + this.emitLine("converter.WriteJson(writer, ", variable, ", serializer);"); + } else { + this.emitLine(this.serializeValueCode(variable), ";"); + } + + emitFinish([]); + return true; + } else if (xfer instanceof ArrayEncodingTransformer) { + this.emitLine("writer.WriteStartArray();"); + const itemVariable = "arrayItem"; + this.emitLine("foreach (var ", itemVariable, " in ", variable, ")"); + this.emitBlock(() => { + this.emitTransformer(itemVariable, xfer.itemTransformer, xfer.itemTargetType, () => { + return; + }); + }); + this.emitLine("writer.WriteEndArray();"); + emitFinish([]); + return true; + } else if (xfer instanceof ParseStringTransformer) { + const immediateTargetType = xfer.consumer === undefined ? targetType : xfer.consumer.sourceType; + switch (immediateTargetType.kind) { + case "date-time": + this.emitLine("DateTimeOffset dt;"); + this.emitLine("if (DateTimeOffset.TryParse(", variable, ", out dt))"); + this.emitBlock(() => this.emitConsume("dt", xfer.consumer, targetType, emitFinish)); + break; + case "uuid": + this.emitLine("Guid guid;"); + this.emitLine("if (Guid.TryParse(", variable, ", out guid))"); + this.emitBlock(() => this.emitConsume("guid", xfer.consumer, targetType, emitFinish)); + break; + case "uri": + this.emitLine("try"); + this.emitBlock(() => { + // this.emitLine("var uri = new Uri(", variable, ");"); + // The default value about:blank should never happen, but this way we avoid a null reference warning. + this.emitLine('var uri = new Uri("about:blank");'); + this.emitLine("if (!string.IsNullOrEmpty(stringValue))"); + this.emitBlock(() => { + this.emitLine("uri = new Uri(", variable, ");"); + }); + this.emitConsume("uri", xfer.consumer, targetType, emitFinish); + }); + this.emitLine("catch (UriFormatException) {}"); + break; + case "integer": + this.emitLine("long l;"); + this.emitLine("if (Int64.TryParse(", variable, ", out l))"); + this.emitBlock(() => this.emitConsume("l", xfer.consumer, targetType, emitFinish)); + break; + case "bool": + this.emitLine("bool b;"); + this.emitLine("if (Boolean.TryParse(", variable, ", out b))"); + this.emitBlock(() => this.emitConsume("b", xfer.consumer, targetType, emitFinish)); + break; + default: + return panic(`Parsing string to ${immediateTargetType.kind} not supported`); + } + } else if (xfer instanceof StringifyTransformer) { + switch (xfer.sourceType.kind) { + case "date-time": + return this.emitConsume( + [variable, '.ToString("o", System.Globalization.CultureInfo.InvariantCulture)'], + xfer.consumer, + targetType, + emitFinish + ); + case "uuid": + return this.emitConsume( + [variable, '.ToString("D", System.Globalization.CultureInfo.InvariantCulture)'], + xfer.consumer, + targetType, + emitFinish + ); + case "integer": + case "uri": + return this.emitConsume([variable, ".ToString()"], xfer.consumer, targetType, emitFinish); + case "bool": + this.emitLine("var boolString = ", variable, ' ? "true" : "false";'); + return this.emitConsume("boolString", xfer.consumer, targetType, emitFinish); + default: + return panic(`Stringifying ${xfer.sourceType.kind} not supported`); + } + } else if (xfer instanceof StringProducerTransformer) { + const value = this.stringCaseValue(directTargetType(xfer.consumer), xfer.result); + return this.emitConsume(value, xfer.consumer, targetType, emitFinish); + } else if (xfer instanceof MinMaxLengthCheckTransformer) { + const min = xfer.minLength; + const max = xfer.maxLength; + const conditions: Sourcelike[] = []; + + if (min !== undefined) { + conditions.push([variable, ".Length >= ", min.toString()]); + } + + if (max !== undefined) { + conditions.push([variable, ".Length <= ", max.toString()]); + } + + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); + this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + return false; + } else if (xfer instanceof MinMaxValueTransformer) { + const min = xfer.minimum; + const max = xfer.maximum; + const conditions: Sourcelike[] = []; + + if (min !== undefined) { + conditions.push([variable, " >= ", min.toString()]); + } + + if (max !== undefined) { + conditions.push([variable, " <= ", max.toString()]); + } + + this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); + this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + return false; + } else if (xfer instanceof UnionInstantiationTransformer) { + if (!(targetType instanceof UnionType)) { + return panic("Union instantiation transformer must produce a union type"); + } + + const maybeNullable = nullableFromUnion(targetType); + if (maybeNullable !== null) { + emitFinish(variable); + } else { + const unionName = this.nameForNamedType(targetType); + let initializer: Sourcelike; + if (xfer.sourceType.kind === "null") { + initializer = " "; + } else { + const memberName = this.nameForUnionMember(targetType, xfer.sourceType); + initializer = [" ", memberName, " = ", variable, " "]; + } + + emitFinish(["new ", unionName, " {", initializer, "}"]); + } + + return true; + } else { + return panic("Unknown transformer"); + } + + return false; + } + + private emitTransformation(converterName: Name, t: Type): void { + const xf = defined(transformationForType(t)); + const reverse = xf.reverse; + const targetType = xf.targetType; + const xfer = xf.transformer; + const csType = this.csType(targetType); + // const haveNullable = isValueType(targetType); + + // if (haveNullable) { + // converterName = ['Nullable', converterName]; + // csType = [csType, "?"]; + // } + this.emitType( + undefined, + AccessModifier.Internal, + "class", + converterName, + ["JsonConverter<", csType, ">"], + () => { + let canConvertExpr: Sourcelike = ["t == typeof(", csType, ")"]; + this.emitCanConvert(canConvertExpr); + this.ensureBlankLine(); + this.emitReadJson(() => { + // FIXME: It's unsatisfying that we need this. The reason is that we not + // only match T, but also T?. If we didn't, then the T in T? would not be + // deserialized with our converter but with the default one. Can we check + // whether the type is a nullable? + // FIXME: This could duplicate one of the cases handled below in + // `emitDecodeTransformer`. + // if (haveNullable && !(targetType instanceof UnionType)) { + // this.emitLine("if (reader.TokenType == JsonTokenType.Null) return null;"); + // } + + const allHandled = this.emitDecodeTransformer(xfer, targetType, v => + this.emitLine("return ", v, ";") + ); + if (!allHandled) { + this.emitThrow(['"Cannot unmarshal type ', csType, '"']); + } + }, csType); + this.ensureBlankLine(); + this.emitWriteJson( + "value", + () => { + // FIXME: See above. + // if (haveNullable && !(targetType instanceof UnionType)) { + // this.emitLine("if (value == null)"); + // this.emitBlock(() => { + // this.emitLine("writer.WriteNullValue();"); + // this.emitLine("return;"); + // }); + // } + + const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => + this.emitLine("return;") + ); + if (!allHandled) { + this.emitThrow(['"Cannot marshal type ', csType, '"']); + } + }, + csType + ); + this.ensureBlankLine(); + this.emitLine("public static readonly ", converterName, " Singleton = new ", converterName, "();"); + } + ); + } + + protected emitRequiredHelpers(): void { + if (this._needHelpers) { + this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitFromJsonForTopLevel(t, n)); + this.ensureBlankLine(); + this.emitSerializeClass(); + } + + if (this._needHelpers || (this._needAttributes && (this.haveNamedUnions || this.haveEnums))) { + this.ensureBlankLine(); + this.emitConverterClass(); + this.forEachTransformation("leading-and-interposing", (n, t) => this.emitTransformation(n, t)); + this.emitMultiline(` +public class DateOnlyConverter : JsonConverter +{ + private readonly string serializationFormat; + public DateOnlyConverter() : this(null) { } + + public DateOnlyConverter(string? serializationFormat) + { + this.serializationFormat = serializationFormat ?? "yyyy-MM-dd"; + } + + public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var value = reader.GetString(); + return DateOnly.Parse(value!); + } + + public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString(serializationFormat)); +} + +public class TimeOnlyConverter : JsonConverter +{ + private readonly string serializationFormat; + + public TimeOnlyConverter() : this(null) { } + + public TimeOnlyConverter(string? serializationFormat) + { + this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff"; + } + + public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var value = reader.GetString(); + return TimeOnly.Parse(value!); + } + + public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString(serializationFormat)); +} + +internal class IsoDateTimeOffsetConverter : JsonConverter +{ + public override bool CanConvert(Type t) => t == typeof(DateTimeOffset); + + private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; + + private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; + private string? _dateTimeFormat; + private CultureInfo? _culture; + + public DateTimeStyles DateTimeStyles + { + get => _dateTimeStyles; + set => _dateTimeStyles = value; + } + + public string? DateTimeFormat + { + get => _dateTimeFormat ?? string.Empty; + set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; + } + + public CultureInfo Culture + { + get => _culture ?? CultureInfo.CurrentCulture; + set => _culture = value; + } + + public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) + { + string text; + + + if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal + || (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal) + { + value = value.ToUniversalTime(); + } + + text = value.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture); + + writer.WriteStringValue(text); + } + + public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string? dateText = reader.GetString(); + + if (string.IsNullOrEmpty(dateText) == false) + { + if (!string.IsNullOrEmpty(_dateTimeFormat)) + { + return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); + } + else + { + return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles); + } + } + else + { + return default(DateTimeOffset); + } + } + + + public static readonly IsoDateTimeOffsetConverter Singleton = new IsoDateTimeOffsetConverter(); +}`); + } + } + + protected needNamespace(): boolean { + return this._needNamespaces; + } +} diff --git a/packages/quicktype-core/src/language/CSharp/constants.ts b/packages/quicktype-core/src/language/CSharp/constants.ts new file mode 100644 index 000000000..bbe7f3dfb --- /dev/null +++ b/packages/quicktype-core/src/language/CSharp/constants.ts @@ -0,0 +1,79 @@ +export const keywords = [ + "abstract", + "as", + "base", + "bool", + "break", + "byte", + "case", + "catch", + "char", + "checked", + "class", + "const", + "continue", + "decimal", + "default", + "delegate", + "do", + "double", + "else", + "enum", + "event", + "explicit", + "extern", + "false", + "finally", + "fixed", + "float", + "for", + "foreach", + "goto", + "if", + "implicit", + "in", + "int", + "interface", + "internal", + "is", + "lock", + "long", + "namespace", + "new", + "null", + "object", + "operator", + "out", + "override", + "params", + "private", + "protected", + "public", + "readonly", + "ref", + "return", + "sbyte", + "sealed", + "short", + "sizeof", + "stackalloc", + "static", + "string", + "struct", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "uint", + "ulong", + "unchecked", + "unsafe", + "ushort", + "using", + "virtual", + "void", + "volatile", + "while" +] as const; diff --git a/packages/quicktype-core/src/language/CSharp/index.ts b/packages/quicktype-core/src/language/CSharp/index.ts new file mode 100644 index 000000000..c9f7c6d8c --- /dev/null +++ b/packages/quicktype-core/src/language/CSharp/index.ts @@ -0,0 +1,4 @@ +export { CSharpTargetLanguage, cSharpOptions, newtonsoftCSharpOptions, systemTextJsonCSharpOptions } from "./language"; +export { CSharpRenderer } from "./CSharpRenderer"; +export { NewtonsoftCSharpRenderer } from "./NewtonSoftCSharpRenderer"; +export { SystemTextJsonCSharpRenderer } from "./SystemTextJsonCSharpRenderer"; diff --git a/packages/quicktype-core/src/language/CSharp/language.ts b/packages/quicktype-core/src/language/CSharp/language.ts new file mode 100644 index 000000000..b706146b5 --- /dev/null +++ b/packages/quicktype-core/src/language/CSharp/language.ts @@ -0,0 +1,181 @@ +import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { assertNever } from "../../support/Support"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type PrimitiveStringTypeKind, type TransformedStringTypeKind, type Type } from "../../Type"; +import { type StringTypeMapping } from "../../TypeBuilder"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { NewtonsoftCSharpRenderer } from "./NewtonSoftCSharpRenderer"; +import { SystemTextJsonCSharpRenderer } from "./SystemTextJsonCSharpRenderer"; +import { needTransformerForType } from "./utils"; + +export enum Framework { + Newtonsoft = "Newtonsoft", + SystemTextJson = "SystemTextJson" +} + +export type Version = 5 | 6; +export interface OutputFeatures { + attributes: boolean; + helpers: boolean; +} + +export enum AccessModifier { + None = "None", + Public = "Public", + Internal = "Internal" +} + +export type CSharpTypeForAny = "object" | "dynamic"; + +export const cSharpOptions = { + framework: new EnumOption( + "framework", + "Serialization framework", + [ + ["NewtonSoft", Framework.Newtonsoft], + ["SystemTextJson", Framework.SystemTextJson] + ], + "NewtonSoft" + ), + useList: new EnumOption("array-type", "Use T[] or List", [ + ["array", false], + ["list", true] + ]), + dense: new EnumOption( + "density", + "Property density", + [ + ["normal", false], + ["dense", true] + ], + "normal", + "secondary" + ), + // FIXME: Do this via a configurable named eventually. + namespace: new StringOption("namespace", "Generated namespace", "NAME", "QuickType"), + version: new EnumOption( + "csharp-version", + "C# version", + [ + ["5", 5], + ["6", 6] + ], + "6", + "secondary" + ), + virtual: new BooleanOption("virtual", "Generate virtual properties", false), + typeForAny: new EnumOption( + "any-type", + 'Type to use for "any"', + [ + ["object", "object"], + ["dynamic", "dynamic"] + ], + "object", + "secondary" + ), + useDecimal: new EnumOption( + "number-type", + "Type to use for numbers", + [ + ["double", false], + ["decimal", true] + ], + "double", + "secondary" + ), + features: new EnumOption("features", "Output features", [ + ["complete", { namespaces: true, helpers: true, attributes: true }], + ["attributes-only", { namespaces: true, helpers: false, attributes: true }], + ["just-types-and-namespace", { namespaces: true, helpers: false, attributes: false }], + ["just-types", { namespaces: true, helpers: false, attributes: false }] + ]), + baseclass: new EnumOption( + "base-class", + "Base class", + [ + ["EntityData", "EntityData"], + ["Object", undefined] + ], + "Object", + "secondary" + ), + checkRequired: new BooleanOption("check-required", "Fail if required properties are missing", false), + keepPropertyName: new BooleanOption("keep-property-name", "Keep original field name generate", false) +}; + +export const newtonsoftCSharpOptions = Object.assign({}, cSharpOptions, {}); + +export const systemTextJsonCSharpOptions = Object.assign({}, cSharpOptions, {}); + +export class CSharpTargetLanguage extends TargetLanguage { + public constructor() { + super("C#", ["cs", "csharp"], "cs"); + } + + protected getOptions(): Array> { + return [ + cSharpOptions.framework, + cSharpOptions.namespace, + cSharpOptions.version, + cSharpOptions.dense, + cSharpOptions.useList, + cSharpOptions.useDecimal, + cSharpOptions.typeForAny, + cSharpOptions.virtual, + cSharpOptions.features, + cSharpOptions.baseclass, + cSharpOptions.checkRequired, + cSharpOptions.keepPropertyName + ]; + } + + public get stringTypeMapping(): StringTypeMapping { + const mapping: Map = new Map(); + mapping.set("date", "date-time"); + mapping.set("time", "date-time"); + mapping.set("date-time", "date-time"); + mapping.set("uuid", "uuid"); + mapping.set("uri", "uri"); + mapping.set("integer-string", "integer-string"); + mapping.set("bool-string", "bool-string"); + return mapping; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + public needsTransformerForType(t: Type): boolean { + const need = needTransformerForType(t); + return need !== "none" && need !== "nullable"; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ConvenienceRenderer { + const options = getOptionValues(cSharpOptions, untypedOptionValues); + + switch (options.framework) { + case Framework.Newtonsoft: + return new NewtonsoftCSharpRenderer( + this, + renderContext, + getOptionValues(newtonsoftCSharpOptions, untypedOptionValues) + ); + case Framework.SystemTextJson: + return new SystemTextJsonCSharpRenderer( + this, + renderContext, + getOptionValues(systemTextJsonCSharpOptions, untypedOptionValues) + ); + default: + return assertNever(options.framework); + } + } +} diff --git a/packages/quicktype-core/src/language/CSharp/utils.ts b/packages/quicktype-core/src/language/CSharp/utils.ts new file mode 100644 index 000000000..0805f7431 --- /dev/null +++ b/packages/quicktype-core/src/language/CSharp/utils.ts @@ -0,0 +1,133 @@ +import { Type, EnumType, UnionType, ArrayType, PrimitiveType } from "../../Type"; +import { nullableFromUnion } from "../../TypeUtils"; +import { Sourcelike } from "../../Source"; +import { + utf16LegalizeCharacters, + splitIntoWords, + combineWords, + firstUpperWordStyle, + WordInName +} from "../../support/Strings"; +import { panic } from "../../support/Support"; +import { funPrefixNamer } from "../../Naming"; +import { Transformation } from "../../Transformers"; +import { minMaxLengthForType, minMaxValueForType } from "../../attributes/Constraints"; +import unicode from "unicode-properties"; +import { keywords } from "./constants"; + +export function noFollow(t: Type): Type { + return t; +} + +export function needTransformerForType(t: Type): "automatic" | "manual" | "nullable" | "none" { + if (t instanceof UnionType) { + const maybeNullable = nullableFromUnion(t); + if (maybeNullable === null) return "automatic"; + if (needTransformerForType(maybeNullable) === "manual") return "nullable"; + return "none"; + } + if (t instanceof ArrayType) { + const itemsNeed = needTransformerForType(t.items); + if (itemsNeed === "manual" || itemsNeed === "nullable") return "automatic"; + return "none"; + } + if (t instanceof EnumType) return "automatic"; + if (t.kind === "double") return minMaxValueForType(t) !== undefined ? "manual" : "none"; + if (t.kind === "integer-string" || t.kind === "bool-string") return "manual"; + if (t.kind === "string") { + return minMaxLengthForType(t) !== undefined ? "manual" : "none"; + } + return "none"; +} + +export function alwaysApplyTransformation(xf: Transformation): boolean { + const t = xf.targetType; + if (t instanceof EnumType) return true; + if (t instanceof UnionType) return nullableFromUnion(t) === null; + return false; +} + +/** + * The C# type for a given transformed string type. + */ +export function csTypeForTransformedStringType(t: PrimitiveType): Sourcelike { + switch (t.kind) { + case "date-time": + return "DateTimeOffset"; + case "uuid": + return "Guid"; + case "uri": + return "Uri"; + default: + return panic(`Transformed string type ${t.kind} not supported`); + } +} + +export const namingFunction = funPrefixNamer("namer", csNameStyle); +export const namingFunctionKeep = funPrefixNamer("namerKeep", csNameStyleKeep); + +// FIXME: Make a Named? +export const denseJsonPropertyName = "J"; +export const denseRequiredEnumName = "R"; +export const denseNullValueHandlingEnumName = "N"; + +export function isStartCharacter(utf16Unit: number): boolean { + if (unicode.isAlphabetic(utf16Unit)) { + return true; + } + return utf16Unit === 0x5f; // underscore +} + +function isPartCharacter(utf16Unit: number): boolean { + const category: string = unicode.getCategory(utf16Unit); + if (["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0) { + return true; + } + return isStartCharacter(utf16Unit); +} + +const legalizeName = utf16LegalizeCharacters(isPartCharacter); + +export function csNameStyle(original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + firstUpperWordStyle, + firstUpperWordStyle, + firstUpperWordStyle, + firstUpperWordStyle, + "", + isStartCharacter + ); +} + +function csNameStyleKeep(original: string): string { + const words: WordInName[] = [ + { + word: original, + isAcronym: false + } + ]; + + const result = combineWords( + words, + legalizeName, + x => x, + x => x, + x => x, + x => x, + "", + isStartCharacter + ); + + // @ts-expect-error needs strong type + return keywords.includes(result) ? "@" + result : result; +} + +export function isValueType(t: Type): boolean { + if (t instanceof UnionType) { + return nullableFromUnion(t) === null; + } + return ["integer", "double", "bool", "enum", "date-time", "uuid"].indexOf(t.kind) >= 0; +} From 7803d6b75e101298dd8318e5e14eb9c9322d1f37 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 14:50:39 -0700 Subject: [PATCH 61/80] move Crystal to own dir --- .../CrystalRenderer.ts} | 244 +----------------- .../src/language/Crystal/constants.ts | 138 ++++++++++ .../src/language/Crystal/index.ts | 2 + .../src/language/Crystal/language.ts | 24 ++ .../src/language/Crystal/utils.ts | 63 +++++ 5 files changed, 239 insertions(+), 232 deletions(-) rename packages/quicktype-core/src/language/{Crystal.ts => Crystal/CrystalRenderer.ts} (56%) create mode 100644 packages/quicktype-core/src/language/Crystal/constants.ts create mode 100644 packages/quicktype-core/src/language/Crystal/index.ts create mode 100644 packages/quicktype-core/src/language/Crystal/language.ts create mode 100644 packages/quicktype-core/src/language/Crystal/utils.ts diff --git a/packages/quicktype-core/src/language/Crystal.ts b/packages/quicktype-core/src/language/Crystal/CrystalRenderer.ts similarity index 56% rename from packages/quicktype-core/src/language/Crystal.ts rename to packages/quicktype-core/src/language/Crystal/CrystalRenderer.ts index 9816191bc..e699b9b9b 100644 --- a/packages/quicktype-core/src/language/Crystal.ts +++ b/packages/quicktype-core/src/language/Crystal/CrystalRenderer.ts @@ -1,234 +1,14 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { type Option } from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated } from "../Source"; -import { - allLowerWordStyle, - combineWords, - escapeNonPrintableMapper, - firstUpperWordStyle, - intToHex, - isAscii, - isLetterOrUnderscore, - isLetterOrUnderscoreOrDigit, - isPrintable, - legalizeCharacters, - splitIntoWords, - utf32ConcatMap -} from "../support/Strings"; -import { TargetLanguage } from "../TargetLanguage"; -import { type ClassType, type EnumType, type Type, type UnionType } from "../Type"; -import { type FixMeOptionsAnyType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -export class CrystalTargetLanguage extends TargetLanguage { - protected makeRenderer(renderContext: RenderContext): CrystalRenderer { - return new CrystalRenderer(this, renderContext); - } - - public constructor() { - super("Crystal", ["crystal", "cr", "crystallang"], "cr"); - } - - protected get defaultIndentation(): string { - return " "; - } - - protected getOptions(): Array> { - return []; - } -} - -const keywords = [ - "Any", - "Array", - "Atomic", - "Bool", - "Channel", - "Char", - "Class", - "Enum", - "Enumerable", - "Event", - "Extern", - "Exception", - "File", - "Float", - "Float32", - "Float64", - "GC", - "GZip", - "Hash", - "HTML", - "HTTP", - "Int", - "Int128", - "Int16", - "Int32", - "Int64", - "Int8", - "Iterable", - "Link", - "Logger", - "Math", - "Mutex", - "Nil", - "Number", - "JSON", - "IO", - "Object", - "Pointer", - "Proc", - "Process", - "Range", - "Random", - "Regex", - "Reference", - "Set", - "Signal", - "Slice", - "Spec", - "StaticArray", - "String", - "Struct", - "Symbol", - "System", - "TCPServer", - "TCPSocket", - "Socket", - "Tempfile", - "Termios", - "Time", - "Tuple", - "ThreadLocal", - "UDPSocket", - "UInt128", - "UInt16", - "UInt32", - "UInt64", - "UInt8", - "Union", - "UNIXServer", - "UNIXSocket", - "UUID", - "URI", - "VaList", - "Value", - "Void", - "WeakRef", - "XML", - "YAML", - "Zip", - "Zlib", - "abstract", - "alias", - "as", - "as?", - "asm", - "begin", - "break", - "case", - "class", - "def", - "do", - "else", - "elsif", - "end", - "ensure", - "enum", - "extend", - "false", - "for", - "fun", - "if", - "in", - "include", - "instance_sizeof", - "is_a?", - "lib", - "macro", - "module", - "next", - "nil", - "nil?", - "of", - "out", - "pointerof", - "private", - "protected", - "require", - "rescue", - "return", - "select", - "self", - "sizeof", - "struct", - "super", - "then", - "true", - "type", - "typeof", - "uninitialized", - "union", - "unless", - "until", - "when", - "while", - "with", - "yield" -]; - -function isAsciiLetterOrUnderscoreOrDigit(codePoint: number): boolean { - if (!isAscii(codePoint)) { - return false; - } - - return isLetterOrUnderscoreOrDigit(codePoint); -} - -function isAsciiLetterOrUnderscore(codePoint: number): boolean { - if (!isAscii(codePoint)) { - return false; - } - - return isLetterOrUnderscore(codePoint); -} - -const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); - -function crystalStyle(original: string, isSnakeCase: boolean): string { - const words = splitIntoWords(original); - - const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; - - const combined = combineWords( - words, - legalizeName, - wordStyle, - wordStyle, - wordStyle, - wordStyle, - isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore - ); - - return combined === "_" ? "_underscore" : combined; -} - -const snakeNamingFunction = funPrefixNamer("default", (original: string) => crystalStyle(original, true)); -const camelNamingFunction = funPrefixNamer("camel", (original: string) => crystalStyle(original, false)); - -function standardUnicodeCrystalEscape(codePoint: number): string { - if (codePoint <= 0xffff) { - return "\\u{" + intToHex(codePoint, 4) + "}"; - } else { - return "\\u{" + intToHex(codePoint, 6) + "}"; - } -} - -const crystalStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeCrystalEscape)); +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { type ClassType, type EnumType, type Type, type UnionType } from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { camelNamingFunction, crystalStringEscape, snakeNamingFunction } from "./utils"; export class CrystalRenderer extends ConvenienceRenderer { public constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) { @@ -251,7 +31,7 @@ export class CrystalRenderer extends ConvenienceRenderer { return camelNamingFunction; } - protected forbiddenNamesForGlobalNamespace(): string[] { + protected forbiddenNamesForGlobalNamespace(): readonly string[] { return keywords; } diff --git a/packages/quicktype-core/src/language/Crystal/constants.ts b/packages/quicktype-core/src/language/Crystal/constants.ts new file mode 100644 index 000000000..9f9f99c5b --- /dev/null +++ b/packages/quicktype-core/src/language/Crystal/constants.ts @@ -0,0 +1,138 @@ +export const keywords = [ + "Any", + "Array", + "Atomic", + "Bool", + "Channel", + "Char", + "Class", + "Enum", + "Enumerable", + "Event", + "Extern", + "Exception", + "File", + "Float", + "Float32", + "Float64", + "GC", + "GZip", + "Hash", + "HTML", + "HTTP", + "Int", + "Int128", + "Int16", + "Int32", + "Int64", + "Int8", + "Iterable", + "Link", + "Logger", + "Math", + "Mutex", + "Nil", + "Number", + "JSON", + "IO", + "Object", + "Pointer", + "Proc", + "Process", + "Range", + "Random", + "Regex", + "Reference", + "Set", + "Signal", + "Slice", + "Spec", + "StaticArray", + "String", + "Struct", + "Symbol", + "System", + "TCPServer", + "TCPSocket", + "Socket", + "Tempfile", + "Termios", + "Time", + "Tuple", + "ThreadLocal", + "UDPSocket", + "UInt128", + "UInt16", + "UInt32", + "UInt64", + "UInt8", + "Union", + "UNIXServer", + "UNIXSocket", + "UUID", + "URI", + "VaList", + "Value", + "Void", + "WeakRef", + "XML", + "YAML", + "Zip", + "Zlib", + "abstract", + "alias", + "as", + "as?", + "asm", + "begin", + "break", + "case", + "class", + "def", + "do", + "else", + "elsif", + "end", + "ensure", + "enum", + "extend", + "false", + "for", + "fun", + "if", + "in", + "include", + "instance_sizeof", + "is_a?", + "lib", + "macro", + "module", + "next", + "nil", + "nil?", + "of", + "out", + "pointerof", + "private", + "protected", + "require", + "rescue", + "return", + "select", + "self", + "sizeof", + "struct", + "super", + "then", + "true", + "type", + "typeof", + "uninitialized", + "union", + "unless", + "until", + "when", + "while", + "with", + "yield" +] as const; diff --git a/packages/quicktype-core/src/language/Crystal/index.ts b/packages/quicktype-core/src/language/Crystal/index.ts new file mode 100644 index 000000000..d6b0ce5bc --- /dev/null +++ b/packages/quicktype-core/src/language/Crystal/index.ts @@ -0,0 +1,2 @@ +export { CrystalTargetLanguage } from "./language"; +export { CrystalRenderer } from "./CrystalRenderer"; diff --git a/packages/quicktype-core/src/language/Crystal/language.ts b/packages/quicktype-core/src/language/Crystal/language.ts new file mode 100644 index 000000000..ba8c81c67 --- /dev/null +++ b/packages/quicktype-core/src/language/Crystal/language.ts @@ -0,0 +1,24 @@ +import { type RenderContext } from "../../Renderer"; +import { type Option } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType } from "../../types"; + +import { CrystalRenderer } from "./CrystalRenderer"; + +export class CrystalTargetLanguage extends TargetLanguage { + protected makeRenderer(renderContext: RenderContext): CrystalRenderer { + return new CrystalRenderer(this, renderContext); + } + + public constructor() { + super("Crystal", ["crystal", "cr", "crystallang"], "cr"); + } + + protected get defaultIndentation(): string { + return " "; + } + + protected getOptions(): Array> { + return []; + } +} diff --git a/packages/quicktype-core/src/language/Crystal/utils.ts b/packages/quicktype-core/src/language/Crystal/utils.ts new file mode 100644 index 000000000..389447460 --- /dev/null +++ b/packages/quicktype-core/src/language/Crystal/utils.ts @@ -0,0 +1,63 @@ +import { + legalizeCharacters, + splitIntoWords, + isLetterOrUnderscoreOrDigit, + combineWords, + allLowerWordStyle, + firstUpperWordStyle, + intToHex, + utf32ConcatMap, + escapeNonPrintableMapper, + isPrintable, + isAscii, + isLetterOrUnderscore +} from "../../support/Strings"; +import { funPrefixNamer } from "../../Naming"; + +function isAsciiLetterOrUnderscoreOrDigit(codePoint: number): boolean { + if (!isAscii(codePoint)) { + return false; + } + return isLetterOrUnderscoreOrDigit(codePoint); +} + +function isAsciiLetterOrUnderscore(codePoint: number): boolean { + if (!isAscii(codePoint)) { + return false; + } + return isLetterOrUnderscore(codePoint); +} + +const legalizeName = legalizeCharacters(isAsciiLetterOrUnderscoreOrDigit); + +function crystalStyle(original: string, isSnakeCase: boolean): string { + const words = splitIntoWords(original); + + const wordStyle = isSnakeCase ? allLowerWordStyle : firstUpperWordStyle; + + const combined = combineWords( + words, + legalizeName, + wordStyle, + wordStyle, + wordStyle, + wordStyle, + isSnakeCase ? "_" : "", + isAsciiLetterOrUnderscore + ); + + return combined === "_" ? "_underscore" : combined; +} + +export const snakeNamingFunction = funPrefixNamer("default", (original: string) => crystalStyle(original, true)); +export const camelNamingFunction = funPrefixNamer("camel", (original: string) => crystalStyle(original, false)); + +function standardUnicodeCrystalEscape(codePoint: number): string { + if (codePoint <= 0xffff) { + return "\\u{" + intToHex(codePoint, 4) + "}"; + } else { + return "\\u{" + intToHex(codePoint, 6) + "}"; + } +} + +export const crystalStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeCrystalEscape)); From af18056344450e2cc768252eb7913ed26aef2e2d Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:08:30 -0700 Subject: [PATCH 62/80] move CPlusPlus to own dir --- .../CPlusPlusRenderer.ts} | 504 ++---------------- .../src/language/CPlusPlus/constants.ts | 103 ++++ .../src/language/CPlusPlus/index.ts | 2 + .../src/language/CPlusPlus/language.ts | 129 +++++ .../src/language/CPlusPlus/utils.ts | 198 +++++++ 5 files changed, 471 insertions(+), 465 deletions(-) rename packages/quicktype-core/src/language/{CPlusPlus.ts => CPlusPlus/CPlusPlusRenderer.ts} (89%) create mode 100644 packages/quicktype-core/src/language/CPlusPlus/constants.ts create mode 100644 packages/quicktype-core/src/language/CPlusPlus/index.ts create mode 100644 packages/quicktype-core/src/language/CPlusPlus/language.ts create mode 100644 packages/quicktype-core/src/language/CPlusPlus/utils.ts diff --git a/packages/quicktype-core/src/language/CPlusPlus.ts b/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts similarity index 89% rename from packages/quicktype-core/src/language/CPlusPlus.ts rename to packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts index 910f714f9..4b70339f2 100644 --- a/packages/quicktype-core/src/language/CPlusPlus.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts @@ -8,473 +8,47 @@ import { withDefault } from "collection-utils"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../Annotation"; -import { getAccessorName } from "../attributes/AccessorNames"; +import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +import { getAccessorName } from "../../attributes/AccessorNames"; +import { enumCaseValues } from "../../attributes/EnumValues"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Declaration } from "../../DeclarationIR"; +import { DependencyName, type Name, type NameStyle, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike, maybeAnnotated } from "../../Source"; +import { type NamingStyle, makeNameStyle, stringEscape } from "../../support/Strings"; +import { assert, assertNever, defined, numberEnumValues, panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, type Type, UnionType } from "../../Type"; import { - type MinMaxConstraint, - minMaxLengthForType, - minMaxValueForType, - patternForType -} from "../attributes/Constraints"; -import { enumCaseValues } from "../attributes/EnumValues"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Declaration } from "../DeclarationIR"; -import { DependencyName, type Name, type NameStyle, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; + directlyReachableTypes, + isNamedType, + matchType, + nullableFromUnion, + removeNullFromUnion +} from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { type cPlusPlusOptions } from "./language"; import { - BooleanOption, - EnumOption, - type Option, - type OptionValues, - StringOption, - getOptionValues -} from "../RendererOptions"; -import { type Sourcelike, maybeAnnotated } from "../Source"; -import { - type NamingStyle, - isAscii, - isLetterOrUnderscoreOrDigit, - legalizeCharacters, - makeNameStyle, - stringEscape -} from "../support/Strings"; -import { assert, assertNever, defined, numberEnumValues, panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { - ArrayType, - type ClassProperty, - ClassType, - EnumType, - MapType, - type Type, - type TypeKind, - UnionType -} from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { directlyReachableTypes, isNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; -const underscoreValue: [string, NamingStyle] = ["underscore-case", "underscore"]; -const camelValue: [string, NamingStyle] = ["camel-case", "camel"]; -const upperUnderscoreValue: [string, NamingStyle] = ["upper-underscore-case", "upper-underscore"]; -const pascalUpperAcronymsValue: [string, NamingStyle] = ["pascal-case-upper-acronyms", "pascal-upper-acronyms"]; -const camelUpperAcronymsValue: [string, NamingStyle] = ["camel-case-upper-acronyms", "camel-upper-acronyms"]; - -export const cPlusPlusOptions = { - typeSourceStyle: new EnumOption( - "source-style", - "Source code generation type, whether to generate single or multiple source files", - [ - ["single-source", true], - ["multi-source", false] - ], - "single-source", - "secondary" - ), - includeLocation: new EnumOption( - "include-location", - "Whether json.hpp is to be located globally or locally", - [ - ["local-include", true], - ["global-include", false] - ], - "local-include", - "secondary" - ), - codeFormat: new EnumOption( - "code-format", - "Generate classes with getters/setters, instead of structs", - [ - ["with-struct", false], - ["with-getter-setter", true] - ], - "with-getter-setter" - ), - wstring: new EnumOption( - "wstring", - "Store strings using Utf-16 std::wstring, rather than Utf-8 std::string", - [ - ["use-string", false], - ["use-wstring", true] - ], - "use-string" - ), - westConst: new EnumOption( - "const-style", - "Put const to the left/west (const T) or right/east (T const)", - [ - ["west-const", true], - ["east-const", false] - ], - "west-const" - ), - justTypes: new BooleanOption("just-types", "Plain types only", false), - namespace: new StringOption("namespace", "Name of the generated namespace(s)", "NAME", "quicktype"), - enumType: new StringOption("enum-type", "Type of enum class", "NAME", "int", "secondary"), - typeNamingStyle: new EnumOption("type-style", "Naming style for types", [ - pascalValue, - underscoreValue, - camelValue, - upperUnderscoreValue, - pascalUpperAcronymsValue, - camelUpperAcronymsValue - ]), - memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ - underscoreValue, - pascalValue, - camelValue, - upperUnderscoreValue, - pascalUpperAcronymsValue, - camelUpperAcronymsValue - ]), - enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ - upperUnderscoreValue, - underscoreValue, - pascalValue, - camelValue, - pascalUpperAcronymsValue, - camelUpperAcronymsValue - ]), - boost: new BooleanOption("boost", "Require a dependency on boost. Without boost, C++17 is required", true), - hideNullOptional: new BooleanOption("hide-null-optional", "Hide null value for optional field", false) -}; - -export class CPlusPlusTargetLanguage extends TargetLanguage { - public constructor(displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { - super(displayName, names, extension); - } - - protected getOptions(): Array> { - return [ - cPlusPlusOptions.justTypes, - cPlusPlusOptions.namespace, - cPlusPlusOptions.codeFormat, - cPlusPlusOptions.wstring, - cPlusPlusOptions.westConst, - cPlusPlusOptions.typeSourceStyle, - cPlusPlusOptions.includeLocation, - cPlusPlusOptions.typeNamingStyle, - cPlusPlusOptions.memberNamingStyle, - cPlusPlusOptions.enumeratorNamingStyle, - cPlusPlusOptions.enumType, - cPlusPlusOptions.boost, - cPlusPlusOptions.hideNullOptional - ]; - } - - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): CPlusPlusRenderer { - return new CPlusPlusRenderer(this, renderContext, getOptionValues(cPlusPlusOptions, untypedOptionValues)); - } -} - -function constraintsForType(t: Type): - | { - minMax?: MinMaxConstraint; - minMaxLength?: MinMaxConstraint; - pattern?: string; - } - | undefined { - const minMax = minMaxValueForType(t); - const minMaxLength = minMaxLengthForType(t); - const pattern = patternForType(t); - if (minMax === undefined && minMaxLength === undefined && pattern === undefined) return undefined; - return { minMax, minMaxLength, pattern }; -} - -const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); - -const keywords = [ - "alignas", - "alignof", - "and", - "and_eq", - "asm", - "atomic_cancel", - "atomic_commit", - "atomic_noexcept", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "char16_t", - "char32_t", - "class", - "compl", - "concept", - "const", - "constexpr", - "const_cast", - "continue", - "co_await", - "co_return", - "co_yield", - "decltype", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "import", - "inline", - "int", - "long", - "module", - "mutable", - "namespace", - "new", - "noexcept", - "not", - "not_eq", - "nullptr", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "requires", - "return", - "short", - "signed", - "sizeof", - "static", - "static_assert", - "static_cast", - "struct", - "switch", - "synchronized", - "template", - "this", - "thread_local", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq", - "override", - "final", - "transaction_safe", - "transaction_safe_dynamic", - "NULL" -]; - -/// Type to use as an optional if cycle breaking is required -const optionalAsSharedType = "std::shared_ptr"; -/// Factory to use when creating an optional if cycle breaking is required -const optionalFactoryAsSharedType = "std::make_shared"; - -/** - * To be able to support circles in multiple files - - * e.g. class#A using class#B using class#A (obviously not directly, - * but in vector or in variant) we can forward declare them; - */ -export enum IncludeKind { - ForwardDeclare = "ForwardDeclare", - Include = "Include" -} - -// FIXME: make these string enums eventually -export enum GlobalNames { - ClassMemberConstraints = 1, - ClassMemberConstraintException = 2, - ValueTooLowException = 3, - ValueTooHighException = 4, - ValueTooShortException = 5, - ValueTooLongException = 6, - InvalidPatternException = 7, - CheckConstraint = 8 -} - -// FIXME: make these string enums eventually -export enum MemberNames { - MinIntValue = 1, - GetMinIntValue = 2, - SetMinIntValue = 3, - MaxIntValue = 4, - GetMaxIntValue = 5, - SetMaxIntValue = 6, - MinDoubleValue = 7, - GetMinDoubleValue = 8, - SetMinDoubleValue = 9, - MaxDoubleValue = 10, - GetMaxDoubleValue = 11, - SetMaxDoubleValue = 12, - MinLength = 13, - GetMinLength = 14, - SetMinLength = 15, - MaxLength = 16, - GetMaxLength = 17, - SetMaxLength = 18, - Pattern = 19, - GetPattern = 20, - SetPattern = 21 -} - -interface ConstraintMember { - cppConstType?: string; - cppType: string; - getter: MemberNames; - name: MemberNames; - setter: MemberNames; -} - -export interface IncludeRecord { - kind: IncludeKind | undefined /** How to include that */; - typeKind: TypeKind | undefined /** What exactly to include */; -} - -export interface TypeRecord { - forceInclude: boolean; - level: number; - name: Name; - type: Type; - variant: boolean; -} - -/** - * We map each and every unique type to a include kind, e.g. how - * to include the given type - */ -export type IncludeMap = Map; - -export interface TypeContext { - inJsonNamespace: boolean; - needsForwardIndirection: boolean; - needsOptionalIndirection: boolean; -} - -interface StringType { - createStringLiteral: (inner: Sourcelike) => Sourcelike; - emitHelperFunctions: () => void; - getConstType: () => string; - getRegex: () => string; - getSMatch: () => string; - getType: () => string; - wrapEncodingChange: ( - qualifier: Sourcelike[], - fromType: Sourcelike, - toType: Sourcelike, - inner: Sourcelike - ) => Sourcelike; - wrapToString: (inner: Sourcelike) => Sourcelike; -} - -function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { - if (qualified.length === 0) { - return []; - } - - return [qualifier, qualified]; -} - -class WrappingCode { - public constructor( - private readonly start: Sourcelike[], - private readonly end: Sourcelike[] - ) {} - - public wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { - return [addQualifier(qualifier, this.start), inner, this.end]; - } -} - -class BaseString { - public _stringType: string; - - public _constStringType: string; - - public _smatch: string; - - public _regex: string; - - public _stringLiteralPrefix: string; - - public _toString: WrappingCode; - - public _encodingClass: Sourcelike; - - public _encodingFunction: Sourcelike; - - public constructor( - stringType: string, - constStringType: string, - smatch: string, - regex: string, - stringLiteralPrefix: string, - toString: WrappingCode, - encodingClass: string, - encodingFunction: string - ) { - this._stringType = stringType; - this._constStringType = constStringType; - this._smatch = smatch; - this._regex = regex; - this._stringLiteralPrefix = stringLiteralPrefix; - this._toString = toString; - this._encodingClass = encodingClass; - this._encodingFunction = encodingFunction; - } - - public getType(): string { - return this._stringType; - } - - public getConstType(): string { - return this._constStringType; - } - - public getSMatch(): string { - return this._smatch; - } - - public getRegex(): string { - return this._regex; - } - - public createStringLiteral(inner: Sourcelike): Sourcelike { - return [this._stringLiteralPrefix, '"', inner, '"']; - } - - public wrapToString(inner: Sourcelike): Sourcelike { - return this._toString.wrap([], inner); - } -} + BaseString, + type ConstraintMember, + GlobalNames, + IncludeKind, + type IncludeMap, + type IncludeRecord, + MemberNames, + type StringType, + type TypeContext, + type TypeRecord, + WrappingCode, + addQualifier, + constraintsForType, + legalizeName, + optionalAsSharedType, + optionalFactoryAsSharedType +} from "./utils"; export class CPlusPlusRenderer extends ConvenienceRenderer { /** diff --git a/packages/quicktype-core/src/language/CPlusPlus/constants.ts b/packages/quicktype-core/src/language/CPlusPlus/constants.ts new file mode 100644 index 000000000..4ed53bd81 --- /dev/null +++ b/packages/quicktype-core/src/language/CPlusPlus/constants.ts @@ -0,0 +1,103 @@ + +export const keywords = [ + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "constexpr", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "import", + "inline", + "int", + "long", + "module", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + "override", + "final", + "transaction_safe", + "transaction_safe_dynamic", + "NULL" +] as const; diff --git a/packages/quicktype-core/src/language/CPlusPlus/index.ts b/packages/quicktype-core/src/language/CPlusPlus/index.ts new file mode 100644 index 000000000..8ee7d4d66 --- /dev/null +++ b/packages/quicktype-core/src/language/CPlusPlus/index.ts @@ -0,0 +1,2 @@ +export { CPlusPlusTargetLanguage, cPlusPlusOptions } from "./language"; +export { CPlusPlusRenderer } from "./CPlusPlusRenderer"; diff --git a/packages/quicktype-core/src/language/CPlusPlus/language.ts b/packages/quicktype-core/src/language/CPlusPlus/language.ts new file mode 100644 index 000000000..292d21a11 --- /dev/null +++ b/packages/quicktype-core/src/language/CPlusPlus/language.ts @@ -0,0 +1,129 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { type NamingStyle } from "../../support/Strings"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { CPlusPlusRenderer } from "./CPlusPlusRenderer"; + +const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; +const underscoreValue: [string, NamingStyle] = ["underscore-case", "underscore"]; +const camelValue: [string, NamingStyle] = ["camel-case", "camel"]; +const upperUnderscoreValue: [string, NamingStyle] = ["upper-underscore-case", "upper-underscore"]; +const pascalUpperAcronymsValue: [string, NamingStyle] = ["pascal-case-upper-acronyms", "pascal-upper-acronyms"]; +const camelUpperAcronymsValue: [string, NamingStyle] = ["camel-case-upper-acronyms", "camel-upper-acronyms"]; + +export const cPlusPlusOptions = { + typeSourceStyle: new EnumOption( + "source-style", + "Source code generation type, whether to generate single or multiple source files", + [ + ["single-source", true], + ["multi-source", false] + ], + "single-source", + "secondary" + ), + includeLocation: new EnumOption( + "include-location", + "Whether json.hpp is to be located globally or locally", + [ + ["local-include", true], + ["global-include", false] + ], + "local-include", + "secondary" + ), + codeFormat: new EnumOption( + "code-format", + "Generate classes with getters/setters, instead of structs", + [ + ["with-struct", false], + ["with-getter-setter", true] + ], + "with-getter-setter" + ), + wstring: new EnumOption( + "wstring", + "Store strings using Utf-16 std::wstring, rather than Utf-8 std::string", + [ + ["use-string", false], + ["use-wstring", true] + ], + "use-string" + ), + westConst: new EnumOption( + "const-style", + "Put const to the left/west (const T) or right/east (T const)", + [ + ["west-const", true], + ["east-const", false] + ], + "west-const" + ), + justTypes: new BooleanOption("just-types", "Plain types only", false), + namespace: new StringOption("namespace", "Name of the generated namespace(s)", "NAME", "quicktype"), + enumType: new StringOption("enum-type", "Type of enum class", "NAME", "int", "secondary"), + typeNamingStyle: new EnumOption("type-style", "Naming style for types", [ + pascalValue, + underscoreValue, + camelValue, + upperUnderscoreValue, + pascalUpperAcronymsValue, + camelUpperAcronymsValue + ]), + memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ + underscoreValue, + pascalValue, + camelValue, + upperUnderscoreValue, + pascalUpperAcronymsValue, + camelUpperAcronymsValue + ]), + enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ + upperUnderscoreValue, + underscoreValue, + pascalValue, + camelValue, + pascalUpperAcronymsValue, + camelUpperAcronymsValue + ]), + boost: new BooleanOption("boost", "Require a dependency on boost. Without boost, C++17 is required", true), + hideNullOptional: new BooleanOption("hide-null-optional", "Hide null value for optional field", false) +}; + +export class CPlusPlusTargetLanguage extends TargetLanguage { + public constructor(displayName = "C++", names: string[] = ["c++", "cpp", "cplusplus"], extension = "cpp") { + super(displayName, names, extension); + } + + protected getOptions(): Array> { + return [ + cPlusPlusOptions.justTypes, + cPlusPlusOptions.namespace, + cPlusPlusOptions.codeFormat, + cPlusPlusOptions.wstring, + cPlusPlusOptions.westConst, + cPlusPlusOptions.typeSourceStyle, + cPlusPlusOptions.includeLocation, + cPlusPlusOptions.typeNamingStyle, + cPlusPlusOptions.memberNamingStyle, + cPlusPlusOptions.enumeratorNamingStyle, + cPlusPlusOptions.enumType, + cPlusPlusOptions.boost, + cPlusPlusOptions.hideNullOptional + ]; + } + + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): CPlusPlusRenderer { + return new CPlusPlusRenderer(this, renderContext, getOptionValues(cPlusPlusOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/CPlusPlus/utils.ts b/packages/quicktype-core/src/language/CPlusPlus/utils.ts new file mode 100644 index 000000000..d1f8ce652 --- /dev/null +++ b/packages/quicktype-core/src/language/CPlusPlus/utils.ts @@ -0,0 +1,198 @@ +import { Type, TypeKind } from "../../Type"; +import { Name } from "../../Naming"; +import { Sourcelike } from "../../Source"; +import { legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit } from "../../support/Strings"; +import { + minMaxValueForType, + minMaxLengthForType, + patternForType, + MinMaxConstraint +} from "../../attributes/Constraints"; + +export function constraintsForType(t: Type): + | { + minMax?: MinMaxConstraint; + minMaxLength?: MinMaxConstraint; + pattern?: string; + } + | undefined { + const minMax = minMaxValueForType(t); + const minMaxLength = minMaxLengthForType(t); + const pattern = patternForType(t); + if (minMax === undefined && minMaxLength === undefined && pattern === undefined) return undefined; + return { minMax, minMaxLength, pattern }; +} + +export const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); + +/// Type to use as an optional if cycle breaking is required +export const optionalAsSharedType = "std::shared_ptr"; +/// Factory to use when creating an optional if cycle breaking is required +export const optionalFactoryAsSharedType = "std::make_shared"; + +/** + * To be able to support circles in multiple files - + * e.g. class#A using class#B using class#A (obviously not directly, + * but in vector or in variant) we can forward declare them; + */ +export enum IncludeKind { + ForwardDeclare, + Include +} + +export enum GlobalNames { + ClassMemberConstraints, + ClassMemberConstraintException, + ValueTooLowException, + ValueTooHighException, + ValueTooShortException, + ValueTooLongException, + InvalidPatternException, + CheckConstraint +} + +export enum MemberNames { + MinIntValue, + GetMinIntValue, + SetMinIntValue, + MaxIntValue, + GetMaxIntValue, + SetMaxIntValue, + MinDoubleValue, + GetMinDoubleValue, + SetMinDoubleValue, + MaxDoubleValue, + GetMaxDoubleValue, + SetMaxDoubleValue, + MinLength, + GetMinLength, + SetMinLength, + MaxLength, + GetMaxLength, + SetMaxLength, + Pattern, + GetPattern, + SetPattern +} + +export type ConstraintMember = { + name: MemberNames; + getter: MemberNames; + setter: MemberNames; + cppType: string; + cppConstType?: string; +}; + +export type IncludeRecord = { + kind: IncludeKind | undefined /** How to include that */; + typeKind: TypeKind | undefined /** What exactly to include */; +}; + +export type TypeRecord = { + name: Name; + type: Type; + level: number; + variant: boolean; + forceInclude: boolean; +}; + +/** + * We map each and every unique type to a include kind, e.g. how + * to include the given type + */ +export type IncludeMap = Map; + +export type TypeContext = { + needsForwardIndirection: boolean; + needsOptionalIndirection: boolean; + inJsonNamespace: boolean; +}; + +export interface StringType { + getType(): string; + getConstType(): string; + getSMatch(): string; + getRegex(): string; + createStringLiteral(inner: Sourcelike): Sourcelike; + wrapToString(inner: Sourcelike): Sourcelike; + wrapEncodingChange( + qualifier: Sourcelike[], + fromType: Sourcelike, + toType: Sourcelike, + inner: Sourcelike + ): Sourcelike; + emitHelperFunctions(): void; +} + +export function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { + if (qualified.length === 0) { + return []; + } + return [qualifier, qualified]; +} + +export class WrappingCode { + constructor( + private readonly start: Sourcelike[], + private readonly end: Sourcelike[] + ) {} + + wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { + return [addQualifier(qualifier, this.start), inner, this.end]; + } +} + +export class BaseString { + public _stringType: string; + public _constStringType: string; + public _smatch: string; + public _regex: string; + public _stringLiteralPrefix: string; + public _toString: WrappingCode; + public _encodingClass: Sourcelike; + public _encodingFunction: Sourcelike; + + constructor( + stringType: string, + constStringType: string, + smatch: string, + regex: string, + stringLiteralPrefix: string, + toString: WrappingCode, + encodingClass: string, + encodingFunction: string + ) { + this._stringType = stringType; + this._constStringType = constStringType; + this._smatch = smatch; + this._regex = regex; + this._stringLiteralPrefix = stringLiteralPrefix; + this._toString = toString; + this._encodingClass = encodingClass; + this._encodingFunction = encodingFunction; + } + + public getType(): string { + return this._stringType; + } + + public getConstType(): string { + return this._constStringType; + } + + public getSMatch(): string { + return this._smatch; + } + + public getRegex(): string { + return this._regex; + } + + public createStringLiteral(inner: Sourcelike): Sourcelike { + return [this._stringLiteralPrefix, '"', inner, '"']; + } + + public wrapToString(inner: Sourcelike): Sourcelike { + return this._toString.wrap([], inner); + } +} From 73efd2074fe016b0daa30544bc3778a39b5cc749 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:23:53 -0700 Subject: [PATCH 63/80] move CJSON to own dir --- .../{CJSON.ts => CJSON/CJSONRenderer.ts} | 388 ++---------------- .../src/language/CJSON/constants.ts | 123 ++++++ .../src/language/CJSON/index.ts | 2 + .../src/language/CJSON/language.ts | 169 ++++++++ .../src/language/CJSON/utils.ts | 57 +++ 5 files changed, 375 insertions(+), 364 deletions(-) rename packages/quicktype-core/src/language/{CJSON.ts => CJSON/CJSONRenderer.ts} (95%) create mode 100644 packages/quicktype-core/src/language/CJSON/constants.ts create mode 100644 packages/quicktype-core/src/language/CJSON/index.ts create mode 100644 packages/quicktype-core/src/language/CJSON/language.ts create mode 100644 packages/quicktype-core/src/language/CJSON/utils.ts diff --git a/packages/quicktype-core/src/language/CJSON.ts b/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts similarity index 95% rename from packages/quicktype-core/src/language/CJSON.ts rename to packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts index 28499a4b4..9272f0dcd 100644 --- a/packages/quicktype-core/src/language/CJSON.ts +++ b/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts @@ -1,368 +1,28 @@ -// FIXME: NEEDS REFACTOR -/* eslint-disable @typescript-eslint/no-shadow */ -/* eslint-disable @typescript-eslint/naming-convention */ -/** - * CJSON.ts - * This file is used to generate cJSON code with quicktype - * The generated code depends of https://github.com/DaveGamble/cJSON, https://github.com/joelguittet/c-list and https://github.com/joelguittet/c-hashtable - * - * Similarly to C++ generator, it is possible to generate a single header file or multiple header files. - * To generate multiple header files, use the following option: --source-style multi-source - * - * JSON data are represented using structures, and functions in the cJSON style are created to use them. - * To parse json data from json string use the following: struct * data = cJSON_Parse(); - * To get json data from cJSON object use the following: struct * data = cJSON_GetValue(); - * To get cJSON object from json data use the following: cJSON * cjson = cJSON_Create(); - * To print json string from json data use the following: char * string = cJSON_Print(); - * To delete json data use the following: cJSON_Delete(); - * - * TODO list for future enhancements: - * - Management of Class, Union and TopLevel should be mutualized to reduce code size and to permit Union and TopLevel having recursive Array/Map - * - Types check should be added to verify unwanted inputs (for example a Number passed while a String is expected, etc) - * - Constraints should be implemented (verification of Enum values, min/max values for Numbers and min/max length for Strings, regex) - * - Support of pure Any type for example providing a callback from the application to handle these cases dynamically - * See test/languages.ts for the test cases which are not implmented/checked. - */ - -/* Imports */ -import { getAccessorName } from "../attributes/AccessorNames"; -import { enumCaseValues } from "../attributes/EnumValues"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, type NameStyle, type Namer, funPrefixNamer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { EnumOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; +import { getAccessorName } from "../../attributes/AccessorNames"; +import { enumCaseValues } from "../../attributes/EnumValues"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, type NameStyle, type Namer, funPrefixNamer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike } from "../../Source"; +import { type NamingStyle, allUpperWordStyle, makeNameStyle } from "../../support/Strings"; +import { assert, assertNever, defined, numberEnumValues, panic } from "../../support/Support"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, ClassType, EnumType, MapType, type Type, UnionType } from "../../Type"; +import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; + +import { keywords } from "./constants"; +import { type cJSONOptions } from "./language"; import { - type NamingStyle, - allUpperWordStyle, - isAscii, - isLetterOrUnderscoreOrDigit, - legalizeCharacters, - makeNameStyle -} from "../support/Strings"; -import { assert, assertNever, defined, numberEnumValues, panic } from "../support/Support"; -import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, ClassType, EnumType, MapType, type Type, type TypeKind, UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../TypeUtils"; - -/* Naming styles */ -const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; -const underscoreValue: [string, NamingStyle] = ["underscore-case", "underscore"]; -const camelValue: [string, NamingStyle] = ["camel-case", "camel"]; -const upperUnderscoreValue: [string, NamingStyle] = ["upper-underscore-case", "upper-underscore"]; -const pascalUpperAcronymsValue: [string, NamingStyle] = ["pascal-case-upper-acronyms", "pascal-upper-acronyms"]; -const camelUpperAcronymsValue: [string, NamingStyle] = ["camel-case-upper-acronyms", "camel-upper-acronyms"]; - -/* cJSON generator options */ -export const cJSONOptions = { - typeSourceStyle: new EnumOption( - "source-style", - "Source code generation type, whether to generate single or multiple source files", - [ - ["single-source", true], - ["multi-source", false] - ], - "single-source", - "secondary" - ), - typeIntegerSize: new EnumOption( - "integer-size", - "Integer code generation type (int64_t by default)", - [ - ["int8_t", "int8_t"], - ["int16_t", "int16_t"], - ["int32_t", "int32_t"], - ["int64_t", "int64_t"] - ], - "int64_t", - "secondary" - ), - hashtableSize: new StringOption( - "hashtable-size", - "Hashtable size, used when maps are created (64 by default)", - "SIZE", - "64" - ), - addTypedefAlias: new EnumOption( - "typedef-alias", - "Add typedef alias to unions, structs, and enums (no typedef by default)", - [ - ["no-typedef", false], - ["add-typedef", true] - ], - "no-typedef", - "secondary" - ), - printStyle: new EnumOption( - "print-style", - "Which cJSON print should be used (formatted by default)", - [ - ["print-formatted", false], - ["print-unformatted", true] - ], - "print-formatted", - "secondary" - ), - typeNamingStyle: new EnumOption("type-style", "Naming style for types", [ - pascalValue, - underscoreValue, - camelValue, - upperUnderscoreValue, - pascalUpperAcronymsValue, - camelUpperAcronymsValue - ]), - memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ - underscoreValue, - pascalValue, - camelValue, - upperUnderscoreValue, - pascalUpperAcronymsValue, - camelUpperAcronymsValue - ]), - enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ - upperUnderscoreValue, - underscoreValue, - pascalValue, - camelValue, - pascalUpperAcronymsValue, - camelUpperAcronymsValue - ]) -}; - -/* cJSON generator target language */ -export class CJSONTargetLanguage extends TargetLanguage { - /** - * Constructor - * @param displayName: display name - * @params names: names - * @param extension: extension of files - */ - public constructor(displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { - super(displayName, names, extension); - } - - /** - * Return cJSON generator options - * @return cJSON generator options array - */ - protected getOptions(): Array> { - return [ - cJSONOptions.typeSourceStyle, - cJSONOptions.typeIntegerSize, - cJSONOptions.addTypedefAlias, - cJSONOptions.printStyle, - cJSONOptions.hashtableSize, - cJSONOptions.typeNamingStyle, - cJSONOptions.memberNamingStyle, - cJSONOptions.enumeratorNamingStyle - ]; - } - - /** - * Indicate if language support union with both number types - * @return true - */ - public get supportsUnionsWithBothNumberTypes(): boolean { - return true; - } - - /** - * Indicate if language support optional class properties - * @return true - */ - public get supportsOptionalClassProperties(): boolean { - return true; - } + GlobalNames, + IncludeKind, + type IncludeMap, + type IncludeRecord, + type TypeCJSON, + type TypeRecord, + legalizeName +} from "./utils"; - /** - * Create renderer - * @param renderContext: render context - * @param untypedOptionValues - * @return cJSON renderer - */ - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): CJSONRenderer { - return new CJSONRenderer(this, renderContext, getOptionValues(cJSONOptions, untypedOptionValues)); - } -} - -/* Function used to format names */ -const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); - -/* Forbidden names for namespace */ -const keywords = [ - /* C and C++ keywords */ - "alignas", - "alignof", - "and", - "and_eq", - "asm", - "atomic_cancel", - "atomic_commit", - "atomic_noexcept", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "char16_t", - "char32_t", - "class", - "compl", - "concept", - "const", - "constexpr", - "const_cast", - "continue", - "co_await", - "co_return", - "co_yield", - "decltype", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "import", - "inline", - "int", - "long", - "module", - "mutable", - "namespace", - "new", - "noexcept", - "not", - "not_eq", - "nullptr", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "requires", - "restrict", - "return", - "short", - "signed", - "sizeof", - "static", - "static_assert", - "static_cast", - "struct", - "switch", - "synchronized", - "template", - "this", - "thread_local", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "typeof", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq", - "override", - "final", - "transaction_safe", - "transaction_safe_dynamic", - "NULL", - /* cJSON keywords */ - "Array", - "ArrayReference", - "Bool", - "DoubleArray", - "False", - "FloatArray", - "IntArray", - "Object", - "Null", - "Number", - "Raw", - "String", - "StringArray", - "StringReference", - "True" -]; - -/* Used to build forbidden global names */ -export enum GlobalNames { - ClassMemberConstraints = 1, - ClassMemberConstraintException = 2, - ValueTooLowException = 3, - ValueTooHighException = 4, - ValueTooShortException = 5, - ValueTooLongException = 6, - InvalidPatternException = 7, - CheckConstraint = 8 -} - -/* To be able to support circles in multiple files - e.g. class#A using class#B using class#A (obviously not directly) we can forward declare them */ -export enum IncludeKind { - ForwardDeclare = "ForwardDeclare", - Include = "Include" -} - -/* Used to map includes */ -export interface IncludeRecord { - kind: IncludeKind | undefined /* How to include that */; - typeKind: TypeKind | undefined /* What exactly to include */; -} - -/* Used to map includes */ -export interface TypeRecord { - forceInclude: boolean; - level: number; - name: Name; - type: Type; - variant: boolean; -} - -/* Map each and every unique type to a include kind, e.g. how to include the given type */ -export type IncludeMap = Map; - -/* cJSON type */ -export interface TypeCJSON { - addToObject: Sourcelike /* cJSON add to object function */; - cType: Sourcelike /* C type */; - cjsonType: string /* cJSON type */; - createObject: Sourcelike /* cJSON create object function */; - deleteType: Sourcelike /* cJSON delete function */; - getValue: Sourcelike /* cJSON get value function */; - isNullable: boolean /* True if the field is nullable */; - isType: Sourcelike /* cJSON check type function */; - items: TypeCJSON | undefined /* Sub-items, used for arrays and map */; - optionalQualifier: string /* C optional qualifier, empty string if not defined */; -} - -/* cJSON renderer */ export class CJSONRenderer extends ConvenienceRenderer { private currentFilename: string | undefined; /* Current filename */ @@ -3409,7 +3069,7 @@ export class CJSONRenderer extends ConvenienceRenderer { } else { this.emitLine( "list_add_tail(x->value, ", - // @ts-expect-error awaiting refactor + // @ts-expect-error awaiting refactor cJSON.items?.getValue, "(e), sizeof(", cJSON.items?.cType, diff --git a/packages/quicktype-core/src/language/CJSON/constants.ts b/packages/quicktype-core/src/language/CJSON/constants.ts new file mode 100644 index 000000000..cdccf419c --- /dev/null +++ b/packages/quicktype-core/src/language/CJSON/constants.ts @@ -0,0 +1,123 @@ + +/* Forbidden names for namespace */ +export const keywords = [ + /* C and C++ keywords */ + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "constexpr", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "import", + "inline", + "int", + "long", + "module", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "requires", + "restrict", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "typeof", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + "override", + "final", + "transaction_safe", + "transaction_safe_dynamic", + "NULL", + /* cJSON keywords */ + "Array", + "ArrayReference", + "Bool", + "DoubleArray", + "False", + "FloatArray", + "IntArray", + "Object", + "Null", + "Number", + "Raw", + "String", + "StringArray", + "StringReference", + "True" +] as const; diff --git a/packages/quicktype-core/src/language/CJSON/index.ts b/packages/quicktype-core/src/language/CJSON/index.ts new file mode 100644 index 000000000..1534721aa --- /dev/null +++ b/packages/quicktype-core/src/language/CJSON/index.ts @@ -0,0 +1,2 @@ +export { CJSONTargetLanguage, cJSONOptions } from "./language"; +export { CJSONRenderer } from "./CJSONRenderer"; diff --git a/packages/quicktype-core/src/language/CJSON/language.ts b/packages/quicktype-core/src/language/CJSON/language.ts new file mode 100644 index 000000000..fdcde98a7 --- /dev/null +++ b/packages/quicktype-core/src/language/CJSON/language.ts @@ -0,0 +1,169 @@ +/** + * CJSON.ts + * This file is used to generate cJSON code with quicktype + * The generated code depends of https://github.com/DaveGamble/cJSON, https://github.com/joelguittet/c-list and https://github.com/joelguittet/c-hashtable + * + * Similarly to C++ generator, it is possible to generate a single header file or multiple header files. + * To generate multiple header files, use the following option: --source-style multi-source + * + * JSON data are represented using structures, and functions in the cJSON style are created to use them. + * To parse json data from json string use the following: struct * data = cJSON_Parse(); + * To get json data from cJSON object use the following: struct * data = cJSON_GetValue(); + * To get cJSON object from json data use the following: cJSON * cjson = cJSON_Create(); + * To print json string from json data use the following: char * string = cJSON_Print(); + * To delete json data use the following: cJSON_Delete(); + * + * TODO list for future enhancements: + * - Management of Class, Union and TopLevel should be mutualized to reduce code size and to permit Union and TopLevel having recursive Array/Map + * - Types check should be added to verify unwanted inputs (for example a Number passed while a String is expected, etc) + * - Constraints should be implemented (verification of Enum values, min/max values for Numbers and min/max length for Strings, regex) + * - Support of pure Any type for example providing a callback from the application to handle these cases dynamically + * See test/languages.ts for the test cases which are not implmented/checked. + */ + +import { type RenderContext } from "../../Renderer"; +import { EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { type NamingStyle } from "../../support/Strings"; +import { TargetLanguage } from "../../TargetLanguage"; + +import { CJSONRenderer } from "./CJSONRenderer"; + +/* Naming styles */ +const pascalValue: [string, NamingStyle] = ["pascal-case", "pascal"]; +const underscoreValue: [string, NamingStyle] = ["underscore-case", "underscore"]; +const camelValue: [string, NamingStyle] = ["camel-case", "camel"]; +const upperUnderscoreValue: [string, NamingStyle] = ["upper-underscore-case", "upper-underscore"]; +const pascalUpperAcronymsValue: [string, NamingStyle] = ["pascal-case-upper-acronyms", "pascal-upper-acronyms"]; +const camelUpperAcronymsValue: [string, NamingStyle] = ["camel-case-upper-acronyms", "camel-upper-acronyms"]; + +/* cJSON generator options */ +export const cJSONOptions = { + typeSourceStyle: new EnumOption( + "source-style", + "Source code generation type, whether to generate single or multiple source files", + [ + ["single-source", true], + ["multi-source", false] + ], + "single-source", + "secondary" + ), + typeIntegerSize: new EnumOption( + "integer-size", + "Integer code generation type (int64_t by default)", + [ + ["int8_t", "int8_t"], + ["int16_t", "int16_t"], + ["int32_t", "int32_t"], + ["int64_t", "int64_t"] + ], + "int64_t", + "secondary" + ), + hashtableSize: new StringOption( + "hashtable-size", + "Hashtable size, used when maps are created (64 by default)", + "SIZE", + "64" + ), + addTypedefAlias: new EnumOption( + "typedef-alias", + "Add typedef alias to unions, structs, and enums (no typedef by default)", + [ + ["no-typedef", false], + ["add-typedef", true] + ], + "no-typedef", + "secondary" + ), + printStyle: new EnumOption( + "print-style", + "Which cJSON print should be used (formatted by default)", + [ + ["print-formatted", false], + ["print-unformatted", true] + ], + "print-formatted", + "secondary" + ), + typeNamingStyle: new EnumOption("type-style", "Naming style for types", [ + pascalValue, + underscoreValue, + camelValue, + upperUnderscoreValue, + pascalUpperAcronymsValue, + camelUpperAcronymsValue + ]), + memberNamingStyle: new EnumOption("member-style", "Naming style for members", [ + underscoreValue, + pascalValue, + camelValue, + upperUnderscoreValue, + pascalUpperAcronymsValue, + camelUpperAcronymsValue + ]), + enumeratorNamingStyle: new EnumOption("enumerator-style", "Naming style for enumerators", [ + upperUnderscoreValue, + underscoreValue, + pascalValue, + camelValue, + pascalUpperAcronymsValue, + camelUpperAcronymsValue + ]) +}; + +/* cJSON generator target language */ +export class CJSONTargetLanguage extends TargetLanguage { + /** + * Constructor + * @param displayName: display name + * @params names: names + * @param extension: extension of files + */ + public constructor(displayName = "C (cJSON)", names: string[] = ["cjson", "cJSON"], extension = "h") { + super(displayName, names, extension); + } + + /** + * Return cJSON generator options + * @return cJSON generator options array + */ + protected getOptions(): Array> { + return [ + cJSONOptions.typeSourceStyle, + cJSONOptions.typeIntegerSize, + cJSONOptions.addTypedefAlias, + cJSONOptions.printStyle, + cJSONOptions.hashtableSize, + cJSONOptions.typeNamingStyle, + cJSONOptions.memberNamingStyle, + cJSONOptions.enumeratorNamingStyle + ]; + } + + /** + * Indicate if language support union with both number types + * @return true + */ + public get supportsUnionsWithBothNumberTypes(): boolean { + return true; + } + + /** + * Indicate if language support optional class properties + * @return true + */ + public get supportsOptionalClassProperties(): boolean { + return true; + } + + /** + * Create renderer + * @param renderContext: render context + * @param untypedOptionValues + * @return cJSON renderer + */ + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): CJSONRenderer { + return new CJSONRenderer(this, renderContext, getOptionValues(cJSONOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/CJSON/utils.ts b/packages/quicktype-core/src/language/CJSON/utils.ts new file mode 100644 index 000000000..c2ee37de8 --- /dev/null +++ b/packages/quicktype-core/src/language/CJSON/utils.ts @@ -0,0 +1,57 @@ +import { Type, TypeKind } from "../../Type"; +import { Name } from "../../Naming"; +import { Sourcelike } from "../../Source"; +import { legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit } from "../../support/Strings"; + +/* Function used to format names */ +export const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); + +/* Used to build forbidden global names */ +export enum GlobalNames { + ClassMemberConstraints, + ClassMemberConstraintException, + ValueTooLowException, + ValueTooHighException, + ValueTooShortException, + ValueTooLongException, + InvalidPatternException, + CheckConstraint +} + +/* To be able to support circles in multiple files - e.g. class#A using class#B using class#A (obviously not directly) we can forward declare them */ +export enum IncludeKind { + ForwardDeclare, + Include +} + +/* Used to map includes */ +export type IncludeRecord = { + kind: IncludeKind | undefined /* How to include that */; + typeKind: TypeKind | undefined /* What exactly to include */; +}; + +/* Used to map includes */ +export type TypeRecord = { + name: Name; + type: Type; + level: number; + variant: boolean; + forceInclude: boolean; +}; + +/* Map each and every unique type to a include kind, e.g. how to include the given type */ +export type IncludeMap = Map; + +/* cJSON type */ +export type TypeCJSON = { + cType: Sourcelike /* C type */; + optionalQualifier: string /* C optional qualifier, empty string if not defined */; + cjsonType: string /* cJSON type */; + isType: Sourcelike /* cJSON check type function */; + getValue: Sourcelike /* cJSON get value function */; + addToObject: Sourcelike /* cJSON add to object function */; + createObject: Sourcelike /* cJSON create object function */; + deleteType: Sourcelike /* cJSON delete function */; + items: TypeCJSON | undefined /* Sub-items, used for arrays and map */; + isNullable: boolean /* True if the field is nullable */; +}; From dc030b8693f8d1814ac851401be48790c984f0ca Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:26:00 -0700 Subject: [PATCH 64/80] fixup! move Golang to own dir --- packages/quicktype-core/src/language/Golang/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/quicktype-core/src/language/Golang/index.ts b/packages/quicktype-core/src/language/Golang/index.ts index e69de29bb..04d294d43 100644 --- a/packages/quicktype-core/src/language/Golang/index.ts +++ b/packages/quicktype-core/src/language/Golang/index.ts @@ -0,0 +1,2 @@ +export { GoTargetLanguage, goOptions } from "./language"; +export { GoRenderer } from "./GolangRenderer"; From 580b6a3cdc324d9a313ef3dc8abebbd53e3b4207 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:26:10 -0700 Subject: [PATCH 65/80] fixup! move JavaScriptPropTypes to own dir --- .../quicktype-core/src/language/JavaScriptPropTypes/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts index e69de29bb..273e81878 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts @@ -0,0 +1,2 @@ +export { JavaScriptPropTypesTargetLanguage, javaScriptPropTypesOptions } from "./language"; +export { JavaScriptPropTypesRenderer } from "./JavaScriptPropTypesRenderer"; From 3b84775ba301b7cb97501569569bab4da9888e27 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:26:19 -0700 Subject: [PATCH 66/80] fixup! move JavaScript to own dir, add unicodeMaps --- packages/quicktype-core/src/language/JavaScript/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/quicktype-core/src/language/JavaScript/index.ts b/packages/quicktype-core/src/language/JavaScript/index.ts index e69de29bb..638d064de 100644 --- a/packages/quicktype-core/src/language/JavaScript/index.ts +++ b/packages/quicktype-core/src/language/JavaScript/index.ts @@ -0,0 +1,2 @@ +export { JavaScriptTargetLanguage, javaScriptOptions } from "./language"; +export { JavaScriptRenderer } from "./JavaScriptRenderer"; From 541e6689fbf6eafeedb16d174bca18d7cb91b540 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:29:24 -0700 Subject: [PATCH 67/80] update reexports --- packages/quicktype-core/src/index.ts | 33 +--------------- packages/quicktype-core/src/language/All.ts | 38 +++++++++---------- packages/quicktype-core/src/language/index.ts | 26 +++++++++++++ 3 files changed, 46 insertions(+), 51 deletions(-) create mode 100644 packages/quicktype-core/src/language/index.ts diff --git a/packages/quicktype-core/src/index.ts b/packages/quicktype-core/src/index.ts index 0fb6d92a6..6da647b12 100644 --- a/packages/quicktype-core/src/index.ts +++ b/packages/quicktype-core/src/index.ts @@ -84,35 +84,4 @@ export { removeNullFromUnion, matchType, nullableFromUnion } from "./TypeUtils"; export { ConvenienceRenderer } from "./ConvenienceRenderer"; export { uriTypeAttributeKind } from "./attributes/URIAttributes"; -export { CJSONTargetLanguage, CJSONRenderer, cJSONOptions } from "./language/CJSON"; -export { CPlusPlusTargetLanguage, CPlusPlusRenderer, cPlusPlusOptions } from "./language/CPlusPlus"; -export { CSharpTargetLanguage, cSharpOptions, CSharpRenderer } from "./language/CSharp"; -export { PythonTargetLanguage, PythonRenderer, pythonOptions } from "./language/Python"; -export { GoTargetLanguage, GoRenderer, goOptions } from "./language/Golang"; -export { ObjectiveCTargetLanguage, ObjectiveCRenderer, objcOptions } from "./language/Objective-C"; -export { JavaTargetLanguage, JavaRenderer, javaOptions } from "./language/Java"; -export { JavaScriptTargetLanguage, JavaScriptRenderer, javaScriptOptions } from "./language/JavaScript"; -export { - JavaScriptPropTypesTargetLanguage, - JavaScriptPropTypesRenderer, - javaScriptPropTypesOptions -} from "./language/JavaScriptPropTypes"; -export { - TypeScriptTargetLanguage, - TypeScriptRenderer, - FlowTargetLanguage, - FlowRenderer, - tsFlowOptions -} from "./language/TypeScriptFlow"; -export { SwiftTargetLanguage, SwiftRenderer, swiftOptions } from "./language/Swift"; -export { KotlinTargetLanguage, KotlinRenderer, kotlinOptions } from "./language/Kotlin"; -export { Scala3TargetLanguage, Scala3Renderer, scala3Options } from "./language/Scala3"; -export { SmithyTargetLanguage, Smithy4sRenderer, SmithyOptions } from "./language/Smithy4s"; -export { ElmTargetLanguage, ElmRenderer, elmOptions } from "./language/Elm"; -export { JSONSchemaTargetLanguage, JSONSchemaRenderer } from "./language/JSONSchema"; -export { RustTargetLanguage, RustRenderer, rustOptions } from "./language/Rust"; -export { RubyTargetLanguage, RubyRenderer, rubyOptions } from "./language/Ruby"; -export { CrystalTargetLanguage, CrystalRenderer } from "./language/Crystal"; -export { HaskellTargetLanguage, HaskellRenderer, haskellOptions } from "./language/Haskell"; -export { DartTargetLanguage, DartRenderer, dartOptions } from "./language/Dart"; -export { ElixirTargetLanguage, ElixirRenderer, elixirOptions } from "./language/Elixir"; +export * from "./language"; diff --git a/packages/quicktype-core/src/language/All.ts b/packages/quicktype-core/src/language/All.ts index 673405d22..227ca4322 100644 --- a/packages/quicktype-core/src/language/All.ts +++ b/packages/quicktype-core/src/language/All.ts @@ -31,33 +31,33 @@ import { FlowTargetLanguage, TypeScriptTargetLanguage } from "./TypeScriptFlow"; import { TypeScriptZodTargetLanguage } from "./TypeScriptZod"; export const all: TargetLanguage[] = [ - new CSharpTargetLanguage(), - new GoTargetLanguage(), - new RustTargetLanguage(), - new CrystalTargetLanguage(), new CJSONTargetLanguage(), new CPlusPlusTargetLanguage(), - new ObjectiveCTargetLanguage(), + new CrystalTargetLanguage(), + new CSharpTargetLanguage(), + new DartTargetLanguage(), + new ElixirTargetLanguage(), + new ElmTargetLanguage(), + new FlowTargetLanguage(), + new GoTargetLanguage(), + new HaskellTargetLanguage(), new JavaTargetLanguage(), - new TypeScriptTargetLanguage(), new JavaScriptTargetLanguage(), new JavaScriptPropTypesTargetLanguage(), - new FlowTargetLanguage(), - new SwiftTargetLanguage(), - new Scala3TargetLanguage(), - new SmithyTargetLanguage(), - new KotlinTargetLanguage(), - new ElmTargetLanguage(), new JSONSchemaTargetLanguage(), - new RubyTargetLanguage(), - new DartTargetLanguage(), - new PythonTargetLanguage("Python", ["python", "py"], "py"), + new KotlinTargetLanguage(), + new ObjectiveCTargetLanguage(), + new PhpTargetLanguage(), new PikeTargetLanguage(), - new HaskellTargetLanguage(), - new TypeScriptZodTargetLanguage(), + new PythonTargetLanguage("Python", ["python", "py"], "py"), + new RubyTargetLanguage(), + new RustTargetLanguage(), + new Scala3TargetLanguage(), + new SmithyTargetLanguage(), + new SwiftTargetLanguage(), + new TypeScriptTargetLanguage(), new TypeScriptEffectSchemaTargetLanguage(), - new ElixirTargetLanguage(), - new PhpTargetLanguage() + new TypeScriptZodTargetLanguage() ]; export function languageNamed(name: string, targetLanguages?: TargetLanguage[]): TargetLanguage | undefined { diff --git a/packages/quicktype-core/src/language/index.ts b/packages/quicktype-core/src/language/index.ts new file mode 100644 index 000000000..024a52494 --- /dev/null +++ b/packages/quicktype-core/src/language/index.ts @@ -0,0 +1,26 @@ +export * from "./CJSON"; +export * from "./CPlusPlus"; +export * from "./Crystal"; +export * from "./CSharp"; +export * from "./Dart"; +export * from "./Elixir"; +export * from "./Elm"; +export * from "./Golang"; +export * from "./Haskell"; +export * from "./Java"; +export * from "./JavaScript"; +export * from "./JavaScriptPropTypes"; +export * from "./JSONSchema"; +export * from "./Kotlin"; +export * from "./Objective-C"; +export * from "./Php"; +export * from "./Pike"; +export * from "./Python"; +export * from "./Ruby"; +export * from "./Rust"; +export * from "./Scala3"; +export * from "./Smithy4s"; +export * from "./Swift"; +export * from "./TypeScriptFlow"; +export * from "./TypeScriptEffectSchema"; +export * from "./TypeScriptZod"; From fe4934dffea1df36abe51ce113758270be2383ee Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:31:26 -0700 Subject: [PATCH 68/80] fix types errors --- packages/quicktype-core/src/language/JavaScript/index.ts | 2 +- .../TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts | 2 +- packages/quicktype-core/src/language/TypeScriptFlow/utils.ts | 4 ++-- .../src/language/TypeScriptZod/TypeScriptZodRenderer.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/quicktype-core/src/language/JavaScript/index.ts b/packages/quicktype-core/src/language/JavaScript/index.ts index 638d064de..0288d9f7b 100644 --- a/packages/quicktype-core/src/language/JavaScript/index.ts +++ b/packages/quicktype-core/src/language/JavaScript/index.ts @@ -1,2 +1,2 @@ export { JavaScriptTargetLanguage, javaScriptOptions } from "./language"; -export { JavaScriptRenderer } from "./JavaScriptRenderer"; +export { JavaScriptRenderer, JavaScriptTypeAnnotations } from "./JavaScriptRenderer"; diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts index 2c9946b4c..f06807a39 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts @@ -20,7 +20,7 @@ import { panic } from "../../support/Support"; import { type TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, EnumType, MapType, type ObjectType, type Type } from "../../Type"; import { matchType } from "../../TypeUtils"; -import { legalizeName } from "../JavaScript"; +import { legalizeName } from "../JavaScript/utils"; import { type typeScriptEffectSchemaOptions } from "./language"; diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts b/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts index 731f46cdd..6f274b062 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts @@ -1,5 +1,5 @@ -import { legalizeName } from "../../language/JavaScript"; -import { isES3IdentifierStart } from "../../language/JavaScriptUnicodeMaps"; +import { isES3IdentifierStart } from "../JavaScript/unicodeMaps"; +import { legalizeName } from "../JavaScript/utils"; import { utf16StringEscape } from "../../support/Strings"; export const tsFlowTypeAnnotations = { diff --git a/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts b/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts index 6b06e1a45..a886288aa 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts @@ -28,7 +28,7 @@ import { type Type } from "../../Type"; import { matchType } from "../../TypeUtils"; -import { legalizeName } from "../JavaScript"; +import { legalizeName } from "../JavaScript/utils"; import { type typeScriptZodOptions } from "./language"; From ef431d5fe9007ffedc996fe32c4550e17aaf1706 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:53:00 -0700 Subject: [PATCH 69/80] fix broken imports --- .../JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts index 4dcd6ee91..7c7fe659e 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts @@ -16,7 +16,14 @@ import { } from "../../support/Strings"; import { panic } from "../../support/Support"; import { type TargetLanguage } from "../../TargetLanguage"; -import { type ClassProperty, type ClassType, type ObjectType, PrimitiveType, type Type } from "../../Type"; +import { + type ArrayType, + type ClassProperty, + type ClassType, + type ObjectType, + PrimitiveType, + type Type +} from "../../Type"; import { directlyReachableSingleNamedType, matchType } from "../../TypeUtils"; import { isES3IdentifierStart } from "../JavaScript/unicodeMaps"; import { legalizeName } from "../JavaScript/utils"; From 6965905fce47e34c06282ff6f7528302009b21e1 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sat, 13 Apr 2024 15:53:10 -0700 Subject: [PATCH 70/80] update test/languages --- test/languages.ts | 58 +++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/test/languages.ts b/test/languages.ts index 51f76bb4a..f90e82f28 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -70,7 +70,7 @@ export const CSharpLanguage: Language = { { "number-type": "decimal" }, { "any-type": "dynamic" } ], - sourceFiles: ["src/language/CSharp.ts"] + sourceFiles: ["src/language/CSharp/index/index.ts"] }; export const CSharpLanguageSystemTextJson: Language = { @@ -102,7 +102,7 @@ export const CSharpLanguageSystemTextJson: Language = { { "number-type": "decimal" }, { "any-type": "dynamic" } ], - sourceFiles: ["src/language/CSharp.ts"] + sourceFiles: ["src/language/CSharp/index.ts"] }; export const JavaLanguage: Language = { @@ -125,7 +125,7 @@ export const JavaLanguage: Language = { skipSchema: ["keyword-unions.schema"], // generates classes with names that are case-insensitively equal rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/Java.ts"] + sourceFiles: ["src/language/Java/index.ts"] }; export const JavaLanguageWithLegacyDateTime: Language = { @@ -182,7 +182,7 @@ export const PythonLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [{ "python-version": "3.5" }], - sourceFiles: ["src/language/Python.ts"] + sourceFiles: ["src/language/Python/index.ts"] }; export const RustLanguage: Language = { @@ -224,7 +224,7 @@ export const RustLanguage: Language = { { visibility: "private" }, { visibility: "public" } ], - sourceFiles: ["src/language/Rust.ts"] + sourceFiles: ["src/language/Rust/index.ts"] }; export const CrystalLanguage: Language = { @@ -263,7 +263,7 @@ export const CrystalLanguage: Language = { skipMiscJSON: false, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Crystal.ts"] + sourceFiles: ["src/language/Crystal/index.ts"] }; export const RubyLanguage: Language = { @@ -405,7 +405,7 @@ export const GoLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Golang.ts"] + sourceFiles: ["src/language/Golang/index.ts"] }; export const CJSONLanguage: Language = { @@ -483,7 +483,7 @@ export const CJSONLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [{ "source-style": "single-source" }], - sourceFiles: ["src/language/CJSON.ts"] + sourceFiles: ["src/language/CJSON/index.ts"] }; export const CPlusPlusLanguage: Language = { @@ -542,7 +542,7 @@ export const CPlusPlusLanguage: Language = { { "const-style": "east-const" }, { boost: "false" } ], - sourceFiles: ["src/language/CPlusPlus.ts"] + sourceFiles: ["src/language/CPlusPlus/index.ts"] }; export const ElmLanguage: Language = { @@ -614,7 +614,7 @@ export const ElmLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/Elm.ts"] + sourceFiles: ["src/language/Elm/index.ts"] }; export const SwiftLanguage: Language = { @@ -702,7 +702,7 @@ export const SwiftLanguage: Language = { { protocol: "equatable" }, ["simple-object.json", { protocol: "hashable" }] ], - sourceFiles: ["src/language/Swift.ts"] + sourceFiles: ["src/language/Swift/index.ts"] }; export const ObjectiveCLanguage: Language = { @@ -740,7 +740,7 @@ export const ObjectiveCLanguage: Language = { skipSchema: [], rendererOptions: { functions: "true" }, quickTestRendererOptions: [], - sourceFiles: ["src/language/Objective-C.ts"] + sourceFiles: ["src/language/Objective-C/index.ts"] }; export const TypeScriptLanguage: Language = { @@ -770,7 +770,7 @@ export const TypeScriptLanguage: Language = { ], allowMissingNull: false, features: ["enum", "union", "no-defaults", "strict-optional", "date-time"], - output: "TopLevel.ts", + output: "TopLevel/index.ts", topLevel: "TopLevel", skipJSON: [ "7681c.json" // year 0 is out of range @@ -788,7 +788,7 @@ export const TypeScriptLanguage: Language = { { converters: "all-objects" }, { readonly: "true" } ], - sourceFiles: ["src/language/TypeScript.ts"] + sourceFiles: ["src/language/TypeScript/index.ts"] }; export const JavaScriptLanguage: Language = { @@ -815,7 +815,7 @@ export const JavaScriptLanguage: Language = { { "runtime-typecheck-ignore-unknown-properties": "true" }, { converters: "top-level" } ], - sourceFiles: ["src/language/JavaScript.ts"] + sourceFiles: ["src/language/JavaScript/index.ts"] }; export const JavaScriptPropTypesLanguage: Language = { @@ -847,7 +847,7 @@ export const JavaScriptPropTypesLanguage: Language = { { "runtime-typecheck-ignore-unknown-properties": "true" }, { converters: "top-level" } ], - sourceFiles: ["src/Language/JavaScriptPropTypes.ts"] + sourceFiles: ["src/Language/JavaScriptPropTypes/index.ts"] }; export const FlowLanguage: Language = { @@ -876,7 +876,7 @@ export const FlowLanguage: Language = { { "nice-property-names": "true" }, { "declare-unions": "true" } ], - sourceFiles: ["src/language/Flow.ts"] + sourceFiles: ["src/language/Flow/index.ts"] }; export const Scala3Language: Language = { @@ -956,7 +956,7 @@ I havea no idea how to encode these tests correctly. skipMiscJSON: false, rendererOptions: { framework: "circe" }, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Scala3.ts"] + sourceFiles: ["src/Language/Scala3/index.ts"] }; export const Smithy4sLanguage: Language = { @@ -1022,7 +1022,7 @@ I havea no idea how to encode these tests correctly. skipMiscJSON: false, rendererOptions: { framework: "just-types" }, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Smithy4s.ts"] + sourceFiles: ["src/Language/Smithy4s/index.ts"] }; export const KotlinLanguage: Language = { @@ -1107,7 +1107,7 @@ export const KotlinLanguage: Language = { skipMiscJSON: false, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Kotlin.ts"] + sourceFiles: ["src/Language/Kotlin/index.ts"] }; export const KotlinJacksonLanguage: Language = { @@ -1191,7 +1191,7 @@ export const KotlinJacksonLanguage: Language = { skipMiscJSON: false, rendererOptions: { framework: "jackson" }, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Kotlin.ts"] + sourceFiles: ["src/Language/Kotlin/index.ts"] }; export const DartLanguage: Language = { @@ -1241,7 +1241,7 @@ export const DartLanguage: Language = { skipMiscJSON: true, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Dart.ts"] + sourceFiles: ["src/Language/Dart/index.ts"] }; export const PikeLanguage: Language = { @@ -1294,7 +1294,7 @@ export const PikeLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Pike.ts"] + sourceFiles: ["src/Language/Pike/index.ts"] }; export const HaskellLanguage: Language = { @@ -1383,7 +1383,7 @@ export const HaskellLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/Haskell.ts"] + sourceFiles: ["src/language/Haskell/index.ts"] }; export const PHPLanguage: Language = { @@ -1401,7 +1401,7 @@ export const PHPLanguage: Language = { skipSchema: [], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Php.ts"] + sourceFiles: ["src/Language/Php/index.ts"] }; export const TypeScriptZodLanguage: Language = { @@ -1439,7 +1439,7 @@ export const TypeScriptZodLanguage: Language = { ], allowMissingNull: false, features: ["enum", "union", "no-defaults", "date-time"], - output: "TopLevel.ts", + output: "TopLevel/index.ts", topLevel: "TopLevel", skipJSON: [ // Uses generated schema before it's defined @@ -1519,7 +1519,7 @@ export const TypeScriptZodLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/TypeScriptZod.ts"] + sourceFiles: ["src/language/TypeScriptZod/index.ts"] }; export const TypeScriptEffectSchemaLanguage: Language = { @@ -1557,7 +1557,7 @@ export const TypeScriptEffectSchemaLanguage: Language = { ], allowMissingNull: false, features: ["enum", "union", "no-defaults"], - output: "TopLevel.ts", + output: "TopLevel/index.ts", topLevel: "TopLevel", skipJSON: [ // Uses generated schema before it's defined @@ -1635,7 +1635,7 @@ export const TypeScriptEffectSchemaLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/TypeScriptEffectSchema.ts"] + sourceFiles: ["src/language/TypeScriptEffectSchema/index.ts"] }; export const ElixirLanguage: Language = { From 0c50d86d723552326eafcf99a18a94822a9bacf5 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 08:32:40 -0700 Subject: [PATCH 71/80] move Elixir to own dir --- .../{Elixir.ts => Elixir/ElixirRenderer.ts} | 282 +++--------------- .../src/language/Elixir/constants.ts | 101 +++++++ .../src/language/Elixir/index.ts | 2 + .../src/language/Elixir/language.ts | 33 ++ .../src/language/Elixir/utils.ts | 73 +++++ test/languages.ts | 2 +- 6 files changed, 255 insertions(+), 238 deletions(-) rename packages/quicktype-core/src/language/{Elixir.ts => Elixir/ElixirRenderer.ts} (85%) create mode 100644 packages/quicktype-core/src/language/Elixir/constants.ts create mode 100644 packages/quicktype-core/src/language/Elixir/index.ts create mode 100644 packages/quicktype-core/src/language/Elixir/language.ts create mode 100644 packages/quicktype-core/src/language/Elixir/utils.ts diff --git a/packages/quicktype-core/src/language/Elixir.ts b/packages/quicktype-core/src/language/Elixir/ElixirRenderer.ts similarity index 85% rename from packages/quicktype-core/src/language/Elixir.ts rename to packages/quicktype-core/src/language/Elixir/ElixirRenderer.ts index 3762dae7e..3665836a5 100644 --- a/packages/quicktype-core/src/language/Elixir.ts +++ b/packages/quicktype-core/src/language/Elixir/ElixirRenderer.ts @@ -1,214 +1,22 @@ -import * as unicode from "unicode-properties"; - -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../ConvenienceRenderer"; -import { type Name, Namer } from "../Naming"; -import { type RenderContext } from "../Renderer"; -import { BooleanOption, type Option, type OptionValues, StringOption, getOptionValues } from "../RendererOptions"; -import { type Sourcelike } from "../Source"; +import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { type Name, Namer } from "../../Naming"; +import { type RenderContext } from "../../Renderer"; +import { type OptionValues } from "../../RendererOptions"; +import { type Sourcelike } from "../../Source"; +import { type TargetLanguage } from "../../TargetLanguage"; +import { ArrayType, ClassType, EnumType, MapType, PrimitiveType, type Type, UnionType } from "../../Type"; +import { matchType, nullableFromUnion } from "../../TypeUtils"; + +import { forbiddenModuleNames, reservedWords } from "./constants"; +import { type elixirOptions } from "./language"; import { - allLowerWordStyle, - allUpperWordStyle, - combineWords, - escapeNonPrintableMapper, - firstUpperWordStyle, - intToHex, - isLetterOrUnderscore, - isPrintable, - legalizeCharacters, - splitIntoWords, - utf32ConcatMap -} from "../support/Strings"; -import { TargetLanguage } from "../TargetLanguage"; -import { ArrayType, ClassType, EnumType, MapType, PrimitiveType, type Type, UnionType } from "../Type"; -import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../types"; -import { matchType, nullableFromUnion } from "../TypeUtils"; - -const forbiddenModuleNames = [ - "Access", - "Agent", - "Any", - "Application", - "ArgumentError", - "ArithmeticError", - "Atom", - "BadArityError", - "BadBooleanError", - "BadFunctionError", - "BadMapError", - "BadStructError", - "Base", - "Behaviour", - "Bitwise", - "Calendar", - "CaseClauseError", - "Code", - "Collectable", - "CondClauseError", - "Config", - "Date", - "DateTime", - "Dict", - "DynamicSupervisor", - "Enum", - "ErlangError", - "Exception", - "File", - "Float", - "Function", - "FunctionClauseError", - "GenEvent", - "GenServer", - "HashDict", - "HashSet", - "IO", - "Inspect", - "Integer", - "Kernel", - "KeyError", - "Keyword", - "List", - "Macro", - "Map", - "MapSet", - "MatchError", - "Module", - "Node", - "OptionParser", - "Path", - "Port", - "Process", - "Protocol", - "Range", - "Record", - "Regex", - "Registry", - "RuntimeError", - "Set", - "Stream", - "String", - "StringIO", - "Supervisor", - "SyntaxError", - "System", - "SystemLimitError", - "Task", - "Time", - "TokenMissingError", - "Tuple", - "URI", - "UndefinedFunctionError", - "UnicodeConversionError", - "Version", - "WithClauseError" -]; -const reservedWords = [ - "def", - "defmodule", - "use", - "import", - "alias", - "true", - "false", - "nil", - "when", - "and", - "or", - "not", - "in", - "fn", - "do", - "end", - "catch", - "rescue", - "after", - "else" -]; - -function unicodeEscape(codePoint: number): string { - return `\\u{${intToHex(codePoint, 0)}}`; -} - -function capitalizeFirstLetter(str: string): string { - return str.charAt(0).toUpperCase() + str.slice(1); -} - -const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); - -function escapeDoubleQuotes(str: string): string { - return str.replace(/"/g, '\\"'); -} - -function escapeNewLines(str: string): string { - return str.replace(/\n/g, "\\n"); -} - -export const elixirOptions = { - justTypes: new BooleanOption("just-types", "Plain types only", false), - namespace: new StringOption("namespace", "Specify a module namespace", "NAME", "") -}; - -export class ElixirTargetLanguage extends TargetLanguage { - public constructor() { - super("Elixir", ["elixir"], "ex"); - } - - protected getOptions(): Array> { - return [elixirOptions.justTypes, elixirOptions.namespace]; - } - - public get supportsOptionalClassProperties(): boolean { - return true; - } - - protected get defaultIndentation(): string { - return " "; - } - - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ElixirRenderer { - return new ElixirRenderer(this, renderContext, getOptionValues(elixirOptions, untypedOptionValues)); - } -} - -const isStartCharacter = isLetterOrUnderscore; - -function isPartCharacter(utf16Unit: number): boolean { - const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); -} - -const legalizeName = legalizeCharacters(isPartCharacter); - -function simpleNameStyle(original: string, uppercase: boolean): string { - if (/^[0-9]+$/.test(original)) { - original = `${original}N`; - } - - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - uppercase ? firstUpperWordStyle : allLowerWordStyle, - uppercase ? firstUpperWordStyle : allLowerWordStyle, - allUpperWordStyle, - allUpperWordStyle, - "", - isStartCharacter - ); -} - -function memberNameStyle(original: string): string { - const words = splitIntoWords(original); - return combineWords( - words, - legalizeName, - allLowerWordStyle, - allLowerWordStyle, - allLowerWordStyle, - allLowerWordStyle, - "_", - isStartCharacter - ); -} + capitalizeFirstLetter, + escapeDoubleQuotes, + escapeNewLines, + memberNameStyle, + simpleNameStyle, + stringEscape +} from "./utils"; export class ElixirRenderer extends ConvenienceRenderer { public constructor( @@ -236,7 +44,7 @@ export class ElixirRenderer extends ConvenienceRenderer { } protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { - return { names: reservedWords, includeGlobalForbidden: true }; + return { names: reservedWords as unknown as string[], includeGlobalForbidden: true }; } protected makeNamedTypeNamer(): Namer { @@ -890,8 +698,8 @@ export class ElixirRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitBlock("def from_json(json) do", () => { this.emitMultiline(`json - |> Jason.decode!() - |> from_map()`); + |> Jason.decode!() + |> from_map()`); }); this.ensureBlankLine(); this.emitBlock([`def to_map(${isEmpty ? "_" : ""}struct) do`], () => { @@ -907,8 +715,8 @@ export class ElixirRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitBlock("def to_json(struct) do", () => { this.emitMultiline(`struct - |> to_map() - |> Jason.encode!()`); + |> to_map() + |> Jason.encode!()`); }); }); } @@ -963,40 +771,40 @@ export class ElixirRenderer extends ConvenienceRenderer { this.emitMultiline(`def valid_atom?(value), do: value in @valid_enum_members def valid_atom_string?(value) do - try do - atom = String.to_existing_atom(value) - atom in @valid_enum_members - rescue - ArgumentError -> false - end + try do + atom = String.to_existing_atom(value) + atom in @valid_enum_members + rescue + ArgumentError -> false + end end def encode(value) do - if valid_atom?(value) do - Atom.to_string(value) - else - {:error, "Unexpected value when encoding atom: #{inspect(value)}"} - end + if valid_atom?(value) do + Atom.to_string(value) + else + {:error, "Unexpected value when encoding atom: #{inspect(value)}"} + end end def decode(value) do - if valid_atom_string?(value) do - String.to_existing_atom(value) - else - {:error, "Unexpected value when decoding atom: #{inspect(value)}"} - end + if valid_atom_string?(value) do + String.to_existing_atom(value) + else + {:error, "Unexpected value when decoding atom: #{inspect(value)}"} + end end def from_json(json) do - json - |> Jason.decode!() - |> decode() + json + |> Jason.decode!() + |> decode() end def to_json(data) do - data - |> encode() - |> Jason.encode!() + data + |> encode() + |> Jason.encode!() end`); }); } diff --git a/packages/quicktype-core/src/language/Elixir/constants.ts b/packages/quicktype-core/src/language/Elixir/constants.ts new file mode 100644 index 000000000..89866c9f5 --- /dev/null +++ b/packages/quicktype-core/src/language/Elixir/constants.ts @@ -0,0 +1,101 @@ +export const forbiddenModuleNames = [ + "Access", + "Agent", + "Any", + "Application", + "ArgumentError", + "ArithmeticError", + "Atom", + "BadArityError", + "BadBooleanError", + "BadFunctionError", + "BadMapError", + "BadStructError", + "Base", + "Behaviour", + "Bitwise", + "Calendar", + "CaseClauseError", + "Code", + "Collectable", + "CondClauseError", + "Config", + "Date", + "DateTime", + "Dict", + "DynamicSupervisor", + "Enum", + "ErlangError", + "Exception", + "File", + "Float", + "Function", + "FunctionClauseError", + "GenEvent", + "GenServer", + "HashDict", + "HashSet", + "IO", + "Inspect", + "Integer", + "Kernel", + "KeyError", + "Keyword", + "List", + "Macro", + "Map", + "MapSet", + "MatchError", + "Module", + "Node", + "OptionParser", + "Path", + "Port", + "Process", + "Protocol", + "Range", + "Record", + "Regex", + "Registry", + "RuntimeError", + "Set", + "Stream", + "String", + "StringIO", + "Supervisor", + "SyntaxError", + "System", + "SystemLimitError", + "Task", + "Time", + "TokenMissingError", + "Tuple", + "URI", + "UndefinedFunctionError", + "UnicodeConversionError", + "Version", + "WithClauseError" +] as const; + +export const reservedWords = [ + "def", + "defmodule", + "use", + "import", + "alias", + "true", + "false", + "nil", + "when", + "and", + "or", + "not", + "in", + "fn", + "do", + "end", + "catch", + "rescue", + "after", + "else" +] as const; diff --git a/packages/quicktype-core/src/language/Elixir/index.ts b/packages/quicktype-core/src/language/Elixir/index.ts new file mode 100644 index 000000000..59a6f6eb3 --- /dev/null +++ b/packages/quicktype-core/src/language/Elixir/index.ts @@ -0,0 +1,2 @@ +export { ElixirTargetLanguage, elixirOptions } from "./language"; +export { ElixirRenderer } from "./ElixirRenderer"; diff --git a/packages/quicktype-core/src/language/Elixir/language.ts b/packages/quicktype-core/src/language/Elixir/language.ts new file mode 100644 index 000000000..fceaa7063 --- /dev/null +++ b/packages/quicktype-core/src/language/Elixir/language.ts @@ -0,0 +1,33 @@ +import { type RenderContext } from "../../Renderer"; +import { BooleanOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; +import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; + +import { ElixirRenderer } from "./ElixirRenderer"; + +export const elixirOptions = { + justTypes: new BooleanOption("just-types", "Plain types only", false), + namespace: new StringOption("namespace", "Specify a module namespace", "NAME", "") +}; + +export class ElixirTargetLanguage extends TargetLanguage { + public constructor() { + super("Elixir", ["elixir"], "ex"); + } + + protected getOptions(): Array> { + return [elixirOptions.justTypes, elixirOptions.namespace]; + } + + public get supportsOptionalClassProperties(): boolean { + return true; + } + + protected get defaultIndentation(): string { + return " "; + } + + protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ElixirRenderer { + return new ElixirRenderer(this, renderContext, getOptionValues(elixirOptions, untypedOptionValues)); + } +} diff --git a/packages/quicktype-core/src/language/Elixir/utils.ts b/packages/quicktype-core/src/language/Elixir/utils.ts new file mode 100644 index 000000000..a3aad340d --- /dev/null +++ b/packages/quicktype-core/src/language/Elixir/utils.ts @@ -0,0 +1,73 @@ +import unicode from "unicode-properties"; + +import { + legalizeCharacters, + splitIntoWords, + combineWords, + firstUpperWordStyle, + allUpperWordStyle, + allLowerWordStyle, + utf32ConcatMap, + isPrintable, + escapeNonPrintableMapper, + intToHex, + isLetterOrUnderscore +} from "../../support/Strings"; + +function unicodeEscape(codePoint: number): string { + return `\\u{${intToHex(codePoint, 0)}}`; +} + +export function capitalizeFirstLetter(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); + +export function escapeDoubleQuotes(str: string) { + return str.replace(/"/g, '\\"'); +} + +export function escapeNewLines(str: string) { + return str.replace(/\n/g, "\\n"); +} + +const isStartCharacter = isLetterOrUnderscore; + +function isPartCharacter(utf16Unit: number): boolean { + const category: string = unicode.getCategory(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); +} + +const legalizeName = legalizeCharacters(isPartCharacter); + +export function simpleNameStyle(original: string, uppercase: boolean): string { + if (/^[0-9]+$/.test(original)) { + original = `${original}N`; + } + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + uppercase ? firstUpperWordStyle : allLowerWordStyle, + uppercase ? firstUpperWordStyle : allLowerWordStyle, + allUpperWordStyle, + allUpperWordStyle, + "", + isStartCharacter + ); +} + +export function memberNameStyle(original: string): string { + const words = splitIntoWords(original); + return combineWords( + words, + legalizeName, + allLowerWordStyle, + allLowerWordStyle, + allLowerWordStyle, + allLowerWordStyle, + "_", + isStartCharacter + ); +} diff --git a/test/languages.ts b/test/languages.ts index f90e82f28..e1fa848a1 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -1696,5 +1696,5 @@ export const ElixirLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Elixir.ts"] + sourceFiles: ["src/language/Elixir/index.ts"] }; From 920104bede0a0dcd7e3d560883b263eed16c9327 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 08:53:05 -0700 Subject: [PATCH 72/80] :recycle: --- test/languages.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/languages.ts b/test/languages.ts index e1fa848a1..f1890a7d5 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -70,7 +70,7 @@ export const CSharpLanguage: Language = { { "number-type": "decimal" }, { "any-type": "dynamic" } ], - sourceFiles: ["src/language/CSharp/index/index.ts"] + sourceFiles: ["src/language/CSharp/index.ts"] }; export const CSharpLanguageSystemTextJson: Language = { @@ -770,7 +770,7 @@ export const TypeScriptLanguage: Language = { ], allowMissingNull: false, features: ["enum", "union", "no-defaults", "strict-optional", "date-time"], - output: "TopLevel/index.ts", + output: "TopLevel.ts", topLevel: "TopLevel", skipJSON: [ "7681c.json" // year 0 is out of range @@ -847,7 +847,7 @@ export const JavaScriptPropTypesLanguage: Language = { { "runtime-typecheck-ignore-unknown-properties": "true" }, { converters: "top-level" } ], - sourceFiles: ["src/Language/JavaScriptPropTypes/index.ts"] + sourceFiles: ["src/language/JavaScriptPropTypes/index.ts"] }; export const FlowLanguage: Language = { @@ -956,7 +956,7 @@ I havea no idea how to encode these tests correctly. skipMiscJSON: false, rendererOptions: { framework: "circe" }, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Scala3/index.ts"] + sourceFiles: ["src/language/Scala3/index.ts"] }; export const Smithy4sLanguage: Language = { @@ -1022,7 +1022,7 @@ I havea no idea how to encode these tests correctly. skipMiscJSON: false, rendererOptions: { framework: "just-types" }, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Smithy4s/index.ts"] + sourceFiles: ["src/language/Smithy4s/index.ts"] }; export const KotlinLanguage: Language = { @@ -1107,7 +1107,7 @@ export const KotlinLanguage: Language = { skipMiscJSON: false, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Kotlin/index.ts"] + sourceFiles: ["src/language/Kotlin/index.ts"] }; export const KotlinJacksonLanguage: Language = { @@ -1191,7 +1191,7 @@ export const KotlinJacksonLanguage: Language = { skipMiscJSON: false, rendererOptions: { framework: "jackson" }, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Kotlin/index.ts"] + sourceFiles: ["src/language/Kotlin/index.ts"] }; export const DartLanguage: Language = { @@ -1241,7 +1241,7 @@ export const DartLanguage: Language = { skipMiscJSON: true, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Dart/index.ts"] + sourceFiles: ["src/language/Dart/index.ts"] }; export const PikeLanguage: Language = { @@ -1294,7 +1294,7 @@ export const PikeLanguage: Language = { ], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Pike/index.ts"] + sourceFiles: ["src/language/Pike/index.ts"] }; export const HaskellLanguage: Language = { @@ -1401,7 +1401,7 @@ export const PHPLanguage: Language = { skipSchema: [], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/Language/Php/index.ts"] + sourceFiles: ["src/language/Php/index.ts"] }; export const TypeScriptZodLanguage: Language = { @@ -1439,7 +1439,7 @@ export const TypeScriptZodLanguage: Language = { ], allowMissingNull: false, features: ["enum", "union", "no-defaults", "date-time"], - output: "TopLevel/index.ts", + output: "TopLevel.ts", topLevel: "TopLevel", skipJSON: [ // Uses generated schema before it's defined @@ -1557,7 +1557,7 @@ export const TypeScriptEffectSchemaLanguage: Language = { ], allowMissingNull: false, features: ["enum", "union", "no-defaults"], - output: "TopLevel/index.ts", + output: "TopLevel.ts", topLevel: "TopLevel", skipJSON: [ // Uses generated schema before it's defined From d3a15e70e8b5a23575438aa74e14b95ba86f4b72 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 10:13:42 -0700 Subject: [PATCH 73/80] imported wrong stringEscape for ruby --- packages/quicktype-core/src/language/Ruby/RubyRenderer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts index bae528255..f02e967cd 100644 --- a/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts +++ b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts @@ -3,7 +3,7 @@ import { type Name, Namer } from "../../Naming"; import { type RenderContext } from "../../Renderer"; import { type OptionValues } from "../../RendererOptions"; import { type Sourcelike, modifySource } from "../../Source"; -import { snakeCase, stringEscape } from "../../support/Strings"; +import { snakeCase } from "../../support/Strings"; import { type TargetLanguage } from "../../TargetLanguage"; import { ArrayType, @@ -18,7 +18,7 @@ import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUti import { globals } from "./constants"; import { Strictness, type rubyOptions } from "./language"; -import { forbiddenForObjectProperties, memberNameStyle, simpleNameStyle } from "./utils"; +import { forbiddenForObjectProperties, memberNameStyle, simpleNameStyle, stringEscape } from "./utils"; export class RubyRenderer extends ConvenienceRenderer { public constructor( From 5b1fac0eca315b8b524c00567171268bafb3846c Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 14 Apr 2024 10:20:22 -0700 Subject: [PATCH 74/80] fix wrong stringEscapes --- .../src/language/Dart/DartRenderer.ts | 15 ++------------- .../src/language/Java/JavaRenderer.ts | 4 ++-- .../src/language/Php/PhpRenderer.ts | 3 +-- .../src/language/Swift/SwiftRenderer.ts | 4 ++-- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/packages/quicktype-core/src/language/Dart/DartRenderer.ts b/packages/quicktype-core/src/language/Dart/DartRenderer.ts index 497e47cfb..15ed374aa 100644 --- a/packages/quicktype-core/src/language/Dart/DartRenderer.ts +++ b/packages/quicktype-core/src/language/Dart/DartRenderer.ts @@ -4,7 +4,7 @@ import { DependencyName, type Name, type Namer } from "../../Naming"; import { type RenderContext } from "../../Renderer"; import { type OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated, modifySource } from "../../Source"; -import { decapitalize, snakeCase, stringEscape } from "../../support/Strings"; +import { decapitalize, snakeCase } from "../../support/Strings"; import { defined } from "../../support/Support"; import { type TargetLanguage } from "../../TargetLanguage"; import { type ClassProperty, type ClassType, EnumType, type Type, type UnionType } from "../../Type"; @@ -12,7 +12,7 @@ import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from " import { keywords } from "./constants"; import { type dartOptions } from "./language"; -import { enumCaseNamingFunction, propertyNamingFunction, typeNamingFunction } from "./utils"; +import { enumCaseNamingFunction, propertyNamingFunction, stringEscape, typeNamingFunction } from "./utils"; interface TopLevelDependents { decoder: Name; @@ -175,7 +175,6 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.useFreezed) { this.emitLine("part '", name, ".freezed.dart';"); } - if (!this._options.justTypes) { this.emitLine("part '", name, ".g.dart';"); } @@ -213,7 +212,6 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return "dynamic"; } - return withNullable(this.dartType(maybeNullable, withIssues)); }, transformedStringType => { @@ -232,7 +230,6 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return [list, " == null ? [] : ", "List<", itemType, ">.from(", list, "!.map((x) => ", mapper, "))"]; } - return ["List<", itemType, ">.from(", list, ".map((x) => ", mapper, "))"]; } @@ -303,7 +300,6 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return dynamic; } - return this.fromDynamicExpression(unionType.isNullable, maybeNullable, dynamic); }, transformedStringType => { @@ -317,7 +313,6 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, " == null ? null : ", "DateTime.parse(", dynamic, ")"]; } - return ["DateTime.parse(", dynamic, ")"]; default: return dynamic; @@ -355,7 +350,6 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, "?.", this.toJson, "()"]; } - return [dynamic, ".", this.toJson, "()"]; }, mapType => @@ -373,7 +367,6 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return dynamic; } - return this.toDynamicExpression(unionType.isNullable, maybeNullable, dynamic); }, transformedStringType => { @@ -386,7 +379,6 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, "?.toIso8601String()"]; } - return [dynamic, ".toIso8601String()"]; case "date": if ( @@ -405,7 +397,6 @@ export class DartRenderer extends ConvenienceRenderer { "!.day.toString().padLeft(2, '0')}\"" ]; } - return [ '"${', dynamic, @@ -624,7 +615,6 @@ export class DartRenderer extends ConvenienceRenderer { this.classPropertyCounter++; this.emitLine(`@JsonKey(name: "${jsonName}")`); } - this.emitLine(required ? "required " : "", this.dartType(prop.type, true), " ", name, ","); }); }); @@ -655,7 +645,6 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.useJsonAnnotation) { this.emitLine('@JsonValue("', stringEscape(jsonName), '")'); } - this.emitLine(name, comma); }); }); diff --git a/packages/quicktype-core/src/language/Java/JavaRenderer.ts b/packages/quicktype-core/src/language/Java/JavaRenderer.ts index 6335e60fb..1054df770 100644 --- a/packages/quicktype-core/src/language/Java/JavaRenderer.ts +++ b/packages/quicktype-core/src/language/Java/JavaRenderer.ts @@ -5,7 +5,7 @@ import { type RenderContext } from "../../Renderer"; import { type OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated } from "../../Source"; import { acronymStyle } from "../../support/Acronyms"; -import { capitalize, stringEscape } from "../../support/Strings"; +import { capitalize } from "../../support/Strings"; import { assert, assertNever, defined } from "../../support/Support"; import { type TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, type Type, UnionType } from "../../Type"; @@ -14,7 +14,7 @@ import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeN import { javaKeywords } from "./constants"; import { Java8DateTimeProvider, type JavaDateTimeProvider, JavaLegacyDateTimeProvider } from "./DateTimeProvider"; import { type javaOptions } from "./language"; -import { javaNameStyle } from "./utils"; +import { javaNameStyle, stringEscape } from "./utils"; export class JavaRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; diff --git a/packages/quicktype-core/src/language/Php/PhpRenderer.ts b/packages/quicktype-core/src/language/Php/PhpRenderer.ts index 0c6e3683b..720f5b6e4 100644 --- a/packages/quicktype-core/src/language/Php/PhpRenderer.ts +++ b/packages/quicktype-core/src/language/Php/PhpRenderer.ts @@ -7,14 +7,13 @@ import { type RenderContext } from "../../Renderer"; import { type OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated } from "../../Source"; import { acronymStyle } from "../../support/Acronyms"; -import { stringEscape } from "../../support/Strings"; import { defined } from "../../support/Support"; import { type TargetLanguage } from "../../TargetLanguage"; import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../../TypeUtils"; import { type phpOptions } from "./language"; -import { phpNameStyle } from "./utils"; +import { phpNameStyle, stringEscape } from "./utils"; export interface FunctionNames { readonly from: Name; diff --git a/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts b/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts index 89171de26..18cc7f281 100644 --- a/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts +++ b/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts @@ -7,7 +7,7 @@ import { type RenderContext } from "../../Renderer"; import { type OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated, modifySource } from "../../Source"; import { acronymStyle } from "../../support/Acronyms"; -import { camelCase, stringEscape } from "../../support/Strings"; +import { camelCase } from "../../support/Strings"; import { assert, defined, panic } from "../../support/Support"; import { type TargetLanguage } from "../../TargetLanguage"; import { @@ -24,7 +24,7 @@ import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUti import { keywords } from "./constants"; import { type swiftOptions } from "./language"; -import { MAX_SAMELINE_PROPERTIES, type SwiftProperty, swiftNameStyle } from "./utils"; +import { MAX_SAMELINE_PROPERTIES, type SwiftProperty, stringEscape, swiftNameStyle } from "./utils"; export class SwiftRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; From a22b393608baa560b44bc6d73b8f3e1b7631a67d Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 5 May 2024 15:38:34 -0700 Subject: [PATCH 75/80] fix lint errors --- .../src/language/CJSON/CJSONRenderer.ts | 4 + .../src/language/CJSON/utils.ts | 54 +++---- .../src/language/CPlusPlus/utils.ts | 140 ++++++++++-------- .../src/language/CSharp/utils.ts | 32 ++-- .../src/language/Crystal/utils.ts | 20 +-- .../src/language/Dart/DartRenderer.ts | 11 ++ .../quicktype-core/src/language/Dart/utils.ts | 3 +- .../src/language/Elixir/utils.ts | 25 ++-- .../quicktype-core/src/language/Elm/utils.ts | 27 ++-- .../src/language/Golang/utils.ts | 16 +- .../src/language/Haskell/utils.ts | 14 +- .../src/language/JSONSchema/utils.ts | 6 +- .../src/language/JavaScript/index.ts | 2 +- .../src/language/Kotlin/utils.ts | 1 + .../src/language/Objective-C/utils.ts | 21 +-- .../quicktype-core/src/language/Php/utils.ts | 3 +- .../quicktype-core/src/language/Pike/utils.ts | 2 +- .../src/language/Python/utils.ts | 21 +-- .../quicktype-core/src/language/Ruby/utils.ts | 23 +-- .../quicktype-core/src/language/Rust/utils.ts | 27 ++-- .../src/language/Scala3/utils.ts | 3 +- .../src/language/Smithy4s/utils.ts | 16 +- .../src/language/Swift/utils.ts | 34 ++--- .../src/language/TypeScriptFlow/utils.ts | 2 +- 24 files changed, 279 insertions(+), 228 deletions(-) diff --git a/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts b/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts index 9272f0dcd..6f9dc33b9 100644 --- a/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts +++ b/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts @@ -1,3 +1,7 @@ +// FIXME: NEEDS REFACTOR +/* eslint-disable @typescript-eslint/no-shadow */ +/* eslint-disable @typescript-eslint/naming-convention */ + import { getAccessorName } from "../../attributes/AccessorNames"; import { enumCaseValues } from "../../attributes/EnumValues"; import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; diff --git a/packages/quicktype-core/src/language/CJSON/utils.ts b/packages/quicktype-core/src/language/CJSON/utils.ts index c2ee37de8..2e74a50c7 100644 --- a/packages/quicktype-core/src/language/CJSON/utils.ts +++ b/packages/quicktype-core/src/language/CJSON/utils.ts @@ -1,57 +1,57 @@ -import { Type, TypeKind } from "../../Type"; -import { Name } from "../../Naming"; -import { Sourcelike } from "../../Source"; -import { legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit } from "../../support/Strings"; +import { type Name } from "../../Naming"; +import { type Sourcelike } from "../../Source"; +import { isAscii, isLetterOrUnderscoreOrDigit, legalizeCharacters } from "../../support/Strings"; +import { type Type, type TypeKind } from "../../Type"; /* Function used to format names */ export const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); /* Used to build forbidden global names */ export enum GlobalNames { - ClassMemberConstraints, - ClassMemberConstraintException, - ValueTooLowException, - ValueTooHighException, - ValueTooShortException, - ValueTooLongException, - InvalidPatternException, - CheckConstraint + ClassMemberConstraints = 1, + ClassMemberConstraintException = 2, + ValueTooLowException = 3, + ValueTooHighException = 4, + ValueTooShortException = 5, + ValueTooLongException = 6, + InvalidPatternException = 7, + CheckConstraint = 8 } /* To be able to support circles in multiple files - e.g. class#A using class#B using class#A (obviously not directly) we can forward declare them */ export enum IncludeKind { - ForwardDeclare, - Include + ForwardDeclare = "ForwardDeclare", + Include = "Include" } /* Used to map includes */ -export type IncludeRecord = { +export interface IncludeRecord { kind: IncludeKind | undefined /* How to include that */; typeKind: TypeKind | undefined /* What exactly to include */; -}; +} /* Used to map includes */ -export type TypeRecord = { +export interface TypeRecord { + forceInclude: boolean; + level: number; name: Name; type: Type; - level: number; variant: boolean; - forceInclude: boolean; -}; +} /* Map each and every unique type to a include kind, e.g. how to include the given type */ export type IncludeMap = Map; /* cJSON type */ -export type TypeCJSON = { +export interface TypeCJSON { + addToObject: Sourcelike /* cJSON add to object function */; cType: Sourcelike /* C type */; - optionalQualifier: string /* C optional qualifier, empty string if not defined */; cjsonType: string /* cJSON type */; - isType: Sourcelike /* cJSON check type function */; - getValue: Sourcelike /* cJSON get value function */; - addToObject: Sourcelike /* cJSON add to object function */; createObject: Sourcelike /* cJSON create object function */; deleteType: Sourcelike /* cJSON delete function */; - items: TypeCJSON | undefined /* Sub-items, used for arrays and map */; + getValue: Sourcelike /* cJSON get value function */; isNullable: boolean /* True if the field is nullable */; -}; + isType: Sourcelike /* cJSON check type function */; + items: TypeCJSON | undefined /* Sub-items, used for arrays and map */; + optionalQualifier: string /* C optional qualifier, empty string if not defined */; +} diff --git a/packages/quicktype-core/src/language/CPlusPlus/utils.ts b/packages/quicktype-core/src/language/CPlusPlus/utils.ts index d1f8ce652..f93ce5d54 100644 --- a/packages/quicktype-core/src/language/CPlusPlus/utils.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/utils.ts @@ -1,13 +1,13 @@ -import { Type, TypeKind } from "../../Type"; -import { Name } from "../../Naming"; -import { Sourcelike } from "../../Source"; -import { legalizeCharacters, isAscii, isLetterOrUnderscoreOrDigit } from "../../support/Strings"; import { - minMaxValueForType, + type MinMaxConstraint, minMaxLengthForType, - patternForType, - MinMaxConstraint + minMaxValueForType, + patternForType } from "../../attributes/Constraints"; +import { type Name } from "../../Naming"; +import { type Sourcelike } from "../../Source"; +import { isAscii, isLetterOrUnderscoreOrDigit, legalizeCharacters } from "../../support/Strings"; +import { type Type, type TypeKind } from "../../Type"; export function constraintsForType(t: Type): | { @@ -36,65 +36,67 @@ export const optionalFactoryAsSharedType = "std::make_shared"; * but in vector or in variant) we can forward declare them; */ export enum IncludeKind { - ForwardDeclare, - Include + ForwardDeclare = "ForwardDeclare", + Include = "Include" } +// FIXME: make these string enums eventually export enum GlobalNames { - ClassMemberConstraints, - ClassMemberConstraintException, - ValueTooLowException, - ValueTooHighException, - ValueTooShortException, - ValueTooLongException, - InvalidPatternException, - CheckConstraint + ClassMemberConstraints = 1, + ClassMemberConstraintException = 2, + ValueTooLowException = 3, + ValueTooHighException = 4, + ValueTooShortException = 5, + ValueTooLongException = 6, + InvalidPatternException = 7, + CheckConstraint = 8 } +// FIXME: make these string enums eventually export enum MemberNames { - MinIntValue, - GetMinIntValue, - SetMinIntValue, - MaxIntValue, - GetMaxIntValue, - SetMaxIntValue, - MinDoubleValue, - GetMinDoubleValue, - SetMinDoubleValue, - MaxDoubleValue, - GetMaxDoubleValue, - SetMaxDoubleValue, - MinLength, - GetMinLength, - SetMinLength, - MaxLength, - GetMaxLength, - SetMaxLength, - Pattern, - GetPattern, - SetPattern + MinIntValue = 1, + GetMinIntValue = 2, + SetMinIntValue = 3, + MaxIntValue = 4, + GetMaxIntValue = 5, + SetMaxIntValue = 6, + MinDoubleValue = 7, + GetMinDoubleValue = 8, + SetMinDoubleValue = 9, + MaxDoubleValue = 10, + GetMaxDoubleValue = 11, + SetMaxDoubleValue = 12, + MinLength = 13, + GetMinLength = 14, + SetMinLength = 15, + MaxLength = 16, + GetMaxLength = 17, + SetMaxLength = 18, + Pattern = 19, + GetPattern = 20, + SetPattern = 21 } -export type ConstraintMember = { - name: MemberNames; +export interface ConstraintMember { + cppConstType?: string; + cppType: string; getter: MemberNames; + name: MemberNames; setter: MemberNames; - cppType: string; - cppConstType?: string; -}; +} -export type IncludeRecord = { +export interface IncludeRecord { kind: IncludeKind | undefined /** How to include that */; typeKind: TypeKind | undefined /** What exactly to include */; -}; +} -export type TypeRecord = { +export interface TypeRecord { + forceInclude: boolean; + level: number; name: Name; type: Type; - level: number; variant: boolean; - forceInclude: boolean; -}; +} /** * We map each and every unique type to a include kind, e.g. how @@ -102,57 +104,65 @@ export type TypeRecord = { */ export type IncludeMap = Map; -export type TypeContext = { +export interface TypeContext { + inJsonNamespace: boolean; needsForwardIndirection: boolean; needsOptionalIndirection: boolean; - inJsonNamespace: boolean; -}; +} export interface StringType { - getType(): string; - getConstType(): string; - getSMatch(): string; - getRegex(): string; - createStringLiteral(inner: Sourcelike): Sourcelike; - wrapToString(inner: Sourcelike): Sourcelike; - wrapEncodingChange( + createStringLiteral: (inner: Sourcelike) => Sourcelike; + emitHelperFunctions: () => void; + getConstType: () => string; + getRegex: () => string; + getSMatch: () => string; + getType: () => string; + wrapEncodingChange: ( qualifier: Sourcelike[], fromType: Sourcelike, toType: Sourcelike, inner: Sourcelike - ): Sourcelike; - emitHelperFunctions(): void; + ) => Sourcelike; + wrapToString: (inner: Sourcelike) => Sourcelike; } export function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { if (qualified.length === 0) { return []; } + return [qualifier, qualified]; } -export class WrappingCode { - constructor( +class WrappingCode { + public constructor( private readonly start: Sourcelike[], private readonly end: Sourcelike[] ) {} - wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { + public wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { return [addQualifier(qualifier, this.start), inner, this.end]; } } export class BaseString { public _stringType: string; + public _constStringType: string; + public _smatch: string; + public _regex: string; + public _stringLiteralPrefix: string; + public _toString: WrappingCode; + public _encodingClass: Sourcelike; + public _encodingFunction: Sourcelike; - constructor( + public constructor( stringType: string, constStringType: string, smatch: string, diff --git a/packages/quicktype-core/src/language/CSharp/utils.ts b/packages/quicktype-core/src/language/CSharp/utils.ts index 0805f7431..3b619e672 100644 --- a/packages/quicktype-core/src/language/CSharp/utils.ts +++ b/packages/quicktype-core/src/language/CSharp/utils.ts @@ -1,18 +1,20 @@ -import { Type, EnumType, UnionType, ArrayType, PrimitiveType } from "../../Type"; -import { nullableFromUnion } from "../../TypeUtils"; -import { Sourcelike } from "../../Source"; +import unicode from "unicode-properties"; + +import { minMaxLengthForType, minMaxValueForType } from "../../attributes/Constraints"; +import { funPrefixNamer } from "../../Naming"; +import { type Sourcelike } from "../../Source"; import { - utf16LegalizeCharacters, - splitIntoWords, + type WordInName, combineWords, firstUpperWordStyle, - WordInName + splitIntoWords, + utf16LegalizeCharacters } from "../../support/Strings"; import { panic } from "../../support/Support"; -import { funPrefixNamer } from "../../Naming"; -import { Transformation } from "../../Transformers"; -import { minMaxLengthForType, minMaxValueForType } from "../../attributes/Constraints"; -import unicode from "unicode-properties"; +import { type Transformation } from "../../Transformers"; +import { ArrayType, EnumType, type PrimitiveType, type Type, UnionType } from "../../Type"; +import { nullableFromUnion } from "../../TypeUtils"; + import { keywords } from "./constants"; export function noFollow(t: Type): Type { @@ -26,17 +28,20 @@ export function needTransformerForType(t: Type): "automatic" | "manual" | "nulla if (needTransformerForType(maybeNullable) === "manual") return "nullable"; return "none"; } + if (t instanceof ArrayType) { const itemsNeed = needTransformerForType(t.items); if (itemsNeed === "manual" || itemsNeed === "nullable") return "automatic"; return "none"; } + if (t instanceof EnumType) return "automatic"; if (t.kind === "double") return minMaxValueForType(t) !== undefined ? "manual" : "none"; if (t.kind === "integer-string" || t.kind === "bool-string") return "manual"; if (t.kind === "string") { return minMaxLengthForType(t) !== undefined ? "manual" : "none"; } + return "none"; } @@ -75,14 +80,16 @@ export function isStartCharacter(utf16Unit: number): boolean { if (unicode.isAlphabetic(utf16Unit)) { return true; } + return utf16Unit === 0x5f; // underscore } function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - if (["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0) { + if (["Nd", "Pc", "Mn", "Mc"].includes(category)) { return true; } + return isStartCharacter(utf16Unit); } @@ -129,5 +136,6 @@ export function isValueType(t: Type): boolean { if (t instanceof UnionType) { return nullableFromUnion(t) === null; } - return ["integer", "double", "bool", "enum", "date-time", "uuid"].indexOf(t.kind) >= 0; + + return ["integer", "double", "bool", "enum", "date-time", "uuid"].includes(t.kind); } diff --git a/packages/quicktype-core/src/language/Crystal/utils.ts b/packages/quicktype-core/src/language/Crystal/utils.ts index 389447460..a4d95da50 100644 --- a/packages/quicktype-core/src/language/Crystal/utils.ts +++ b/packages/quicktype-core/src/language/Crystal/utils.ts @@ -1,23 +1,24 @@ +import { funPrefixNamer } from "../../Naming"; import { - legalizeCharacters, - splitIntoWords, - isLetterOrUnderscoreOrDigit, - combineWords, allLowerWordStyle, + combineWords, + escapeNonPrintableMapper, firstUpperWordStyle, intToHex, - utf32ConcatMap, - escapeNonPrintableMapper, - isPrintable, isAscii, - isLetterOrUnderscore + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap } from "../../support/Strings"; -import { funPrefixNamer } from "../../Naming"; function isAsciiLetterOrUnderscoreOrDigit(codePoint: number): boolean { if (!isAscii(codePoint)) { return false; } + return isLetterOrUnderscoreOrDigit(codePoint); } @@ -25,6 +26,7 @@ function isAsciiLetterOrUnderscore(codePoint: number): boolean { if (!isAscii(codePoint)) { return false; } + return isLetterOrUnderscore(codePoint); } diff --git a/packages/quicktype-core/src/language/Dart/DartRenderer.ts b/packages/quicktype-core/src/language/Dart/DartRenderer.ts index 15ed374aa..75508c7b8 100644 --- a/packages/quicktype-core/src/language/Dart/DartRenderer.ts +++ b/packages/quicktype-core/src/language/Dart/DartRenderer.ts @@ -175,6 +175,7 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.useFreezed) { this.emitLine("part '", name, ".freezed.dart';"); } + if (!this._options.justTypes) { this.emitLine("part '", name, ".g.dart';"); } @@ -212,6 +213,7 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return "dynamic"; } + return withNullable(this.dartType(maybeNullable, withIssues)); }, transformedStringType => { @@ -230,6 +232,7 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { return [list, " == null ? [] : ", "List<", itemType, ">.from(", list, "!.map((x) => ", mapper, "))"]; } + return ["List<", itemType, ">.from(", list, ".map((x) => ", mapper, "))"]; } @@ -300,6 +303,7 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return dynamic; } + return this.fromDynamicExpression(unionType.isNullable, maybeNullable, dynamic); }, transformedStringType => { @@ -313,6 +317,7 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, " == null ? null : ", "DateTime.parse(", dynamic, ")"]; } + return ["DateTime.parse(", dynamic, ")"]; default: return dynamic; @@ -350,6 +355,7 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, "?.", this.toJson, "()"]; } + return [dynamic, ".", this.toJson, "()"]; }, mapType => @@ -367,6 +373,7 @@ export class DartRenderer extends ConvenienceRenderer { if (maybeNullable === null) { return dynamic; } + return this.toDynamicExpression(unionType.isNullable, maybeNullable, dynamic); }, transformedStringType => { @@ -379,6 +386,7 @@ export class DartRenderer extends ConvenienceRenderer { ) { return [dynamic, "?.toIso8601String()"]; } + return [dynamic, ".toIso8601String()"]; case "date": if ( @@ -397,6 +405,7 @@ export class DartRenderer extends ConvenienceRenderer { "!.day.toString().padLeft(2, '0')}\"" ]; } + return [ '"${', dynamic, @@ -615,6 +624,7 @@ export class DartRenderer extends ConvenienceRenderer { this.classPropertyCounter++; this.emitLine(`@JsonKey(name: "${jsonName}")`); } + this.emitLine(required ? "required " : "", this.dartType(prop.type, true), " ", name, ","); }); }); @@ -645,6 +655,7 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.useJsonAnnotation) { this.emitLine('@JsonValue("', stringEscape(jsonName), '")'); } + this.emitLine(name, comma); }); }); diff --git a/packages/quicktype-core/src/language/Dart/utils.ts b/packages/quicktype-core/src/language/Dart/utils.ts index 9f34d21f6..2fb4a783d 100644 --- a/packages/quicktype-core/src/language/Dart/utils.ts +++ b/packages/quicktype-core/src/language/Dart/utils.ts @@ -1,3 +1,4 @@ +import { funPrefixNamer } from "../../Naming"; import { allLowerWordStyle, allUpperWordStyle, @@ -14,8 +15,6 @@ import { utf16LegalizeCharacters } from "../../support/Strings"; -import { funPrefixNamer } from "../../Naming"; - export const typeNamingFunction = funPrefixNamer("types", n => dartNameStyle(true, false, n)); export const propertyNamingFunction = funPrefixNamer("properties", n => dartNameStyle(false, false, n)); export const enumCaseNamingFunction = funPrefixNamer("enum-cases", n => dartNameStyle(true, true, n)); diff --git a/packages/quicktype-core/src/language/Elixir/utils.ts b/packages/quicktype-core/src/language/Elixir/utils.ts index a3aad340d..4e81841fe 100644 --- a/packages/quicktype-core/src/language/Elixir/utils.ts +++ b/packages/quicktype-core/src/language/Elixir/utils.ts @@ -1,34 +1,34 @@ import unicode from "unicode-properties"; import { - legalizeCharacters, - splitIntoWords, - combineWords, - firstUpperWordStyle, - allUpperWordStyle, allLowerWordStyle, - utf32ConcatMap, - isPrintable, + allUpperWordStyle, + combineWords, escapeNonPrintableMapper, + firstUpperWordStyle, intToHex, - isLetterOrUnderscore + isLetterOrUnderscore, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap } from "../../support/Strings"; function unicodeEscape(codePoint: number): string { return `\\u{${intToHex(codePoint, 0)}}`; } -export function capitalizeFirstLetter(str: string) { +export function capitalizeFirstLetter(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); -export function escapeDoubleQuotes(str: string) { +export function escapeDoubleQuotes(str: string): string { return str.replace(/"/g, '\\"'); } -export function escapeNewLines(str: string) { +export function escapeNewLines(str: string): string { return str.replace(/\n/g, "\\n"); } @@ -36,7 +36,7 @@ const isStartCharacter = isLetterOrUnderscore; function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } const legalizeName = legalizeCharacters(isPartCharacter); @@ -45,6 +45,7 @@ export function simpleNameStyle(original: string, uppercase: boolean): string { if (/^[0-9]+$/.test(original)) { original = `${original}N`; } + const words = splitIntoWords(original); return combineWords( words, diff --git a/packages/quicktype-core/src/language/Elm/utils.ts b/packages/quicktype-core/src/language/Elm/utils.ts index 9f9ac2b82..2b09265cf 100644 --- a/packages/quicktype-core/src/language/Elm/utils.ts +++ b/packages/quicktype-core/src/language/Elm/utils.ts @@ -1,17 +1,17 @@ -import { UnionType, ClassProperty } from "../../Type"; -import { nullableFromUnion } from "../../TypeUtils"; import { funPrefixNamer } from "../../Naming"; import { - legalizeCharacters, - isLetterOrUnderscoreOrDigit, - isLetterOrUnderscore, - isAscii, - splitIntoWords, + allLowerWordStyle, + allUpperWordStyle, combineWords, firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle + isAscii, + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + legalizeCharacters, + splitIntoWords } from "../../support/Strings"; +import { type ClassProperty, UnionType } from "../../Type"; +import { nullableFromUnion } from "../../TypeUtils"; const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); @@ -32,21 +32,24 @@ function elmNameStyle(original: string, upper: boolean): string { export const upperNamingFunction = funPrefixNamer("upper", n => elmNameStyle(n, true)); export const lowerNamingFunction = funPrefixNamer("lower", n => elmNameStyle(n, false)); -type RequiredOrOptional = { - reqOrOpt: string; +interface RequiredOrOptional { fallback: string; -}; + reqOrOpt: string; +} export function requiredOrOptional(p: ClassProperty): RequiredOrOptional { function optional(fallback: string): RequiredOrOptional { return { reqOrOpt: "Jpipe.optional", fallback }; } + const t = p.type; if (p.isOptional || (t instanceof UnionType && nullableFromUnion(t) !== null)) { return optional(" Nothing"); } + if (t.kind === "null") { return optional(" ()"); } + return { reqOrOpt: "Jpipe.required", fallback: "" }; } diff --git a/packages/quicktype-core/src/language/Golang/utils.ts b/packages/quicktype-core/src/language/Golang/utils.ts index 94f4f5c8a..ce67443af 100644 --- a/packages/quicktype-core/src/language/Golang/utils.ts +++ b/packages/quicktype-core/src/language/Golang/utils.ts @@ -1,14 +1,14 @@ -import { TypeKind, Type, ClassProperty } from "../../Type"; import { funPrefixNamer } from "../../Naming"; import { - legalizeCharacters, - isLetterOrUnderscore, - isLetterOrUnderscoreOrDigit, - splitIntoWords, + allUpperWordStyle, combineWords, firstUpperWordStyle, - allUpperWordStyle + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + legalizeCharacters, + splitIntoWords } from "../../support/Strings"; +import { type ClassProperty, type Type, type TypeKind } from "../../Type"; export const namingFunction = funPrefixNamer("namer", goNameStyle); @@ -33,12 +33,12 @@ export const compoundTypeKinds: TypeKind[] = ["array", "class", "map", "enum"]; export function isValueType(t: Type): boolean { const kind = t.kind; - return primitiveValueTypeKinds.indexOf(kind) >= 0 || kind === "class" || kind === "enum" || kind === "date-time"; + return primitiveValueTypeKinds.includes(kind) || kind === "class" || kind === "enum" || kind === "date-time"; } export function canOmitEmpty(cp: ClassProperty, omitEmptyOption: boolean): boolean { if (!cp.isOptional) return false; if (omitEmptyOption) return true; const t = cp.type; - return ["union", "null", "any"].indexOf(t.kind) < 0; + return !["union", "null", "any"].includes(t.kind); } diff --git a/packages/quicktype-core/src/language/Haskell/utils.ts b/packages/quicktype-core/src/language/Haskell/utils.ts index 951c83760..3f4b1357f 100644 --- a/packages/quicktype-core/src/language/Haskell/utils.ts +++ b/packages/quicktype-core/src/language/Haskell/utils.ts @@ -1,14 +1,14 @@ import { funPrefixNamer } from "../../Naming"; import { - legalizeCharacters, - isLetterOrUnderscoreOrDigit, - isLetterOrUnderscore, - isAscii, - splitIntoWords, + allLowerWordStyle, + allUpperWordStyle, combineWords, firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle + isAscii, + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + legalizeCharacters, + splitIntoWords } from "../../support/Strings"; const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); diff --git a/packages/quicktype-core/src/language/JSONSchema/utils.ts b/packages/quicktype-core/src/language/JSONSchema/utils.ts index 0c66ee4f6..5c3a10e48 100644 --- a/packages/quicktype-core/src/language/JSONSchema/utils.ts +++ b/packages/quicktype-core/src/language/JSONSchema/utils.ts @@ -1,10 +1,10 @@ import { funPrefixNamer } from "../../Naming"; import { - legalizeCharacters, - splitIntoWords, + allUpperWordStyle, combineWords, firstUpperWordStyle, - allUpperWordStyle + legalizeCharacters, + splitIntoWords } from "../../support/Strings"; export const namingFunction = funPrefixNamer("namer", jsonNameStyle); diff --git a/packages/quicktype-core/src/language/JavaScript/index.ts b/packages/quicktype-core/src/language/JavaScript/index.ts index 0288d9f7b..12526b3d9 100644 --- a/packages/quicktype-core/src/language/JavaScript/index.ts +++ b/packages/quicktype-core/src/language/JavaScript/index.ts @@ -1,2 +1,2 @@ export { JavaScriptTargetLanguage, javaScriptOptions } from "./language"; -export { JavaScriptRenderer, JavaScriptTypeAnnotations } from "./JavaScriptRenderer"; +export { JavaScriptRenderer, type JavaScriptTypeAnnotations } from "./JavaScriptRenderer"; diff --git a/packages/quicktype-core/src/language/Kotlin/utils.ts b/packages/quicktype-core/src/language/Kotlin/utils.ts index 1668782ea..69fc8fb0c 100644 --- a/packages/quicktype-core/src/language/Kotlin/utils.ts +++ b/packages/quicktype-core/src/language/Kotlin/utils.ts @@ -46,6 +46,7 @@ function unicodeEscape(codePoint: number): string { return "\\u" + intToHex(codePoint, 4); } +// eslint-disable-next-line @typescript-eslint/naming-convention const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); export function stringEscape(s: string): string { diff --git a/packages/quicktype-core/src/language/Objective-C/utils.ts b/packages/quicktype-core/src/language/Objective-C/utils.ts index fa3929597..7e83f5610 100644 --- a/packages/quicktype-core/src/language/Objective-C/utils.ts +++ b/packages/quicktype-core/src/language/Objective-C/utils.ts @@ -1,14 +1,15 @@ +import unicode from "unicode-properties"; + import { - splitIntoWords, + addPrefixIfNecessary, + allLowerWordStyle, + allUpperWordStyle, combineWords, firstUpperWordStyle, - allUpperWordStyle, - allLowerWordStyle, - utf16LegalizeCharacters, - addPrefixIfNecessary + splitIntoWords, + utf16LegalizeCharacters } from "../../support/Strings"; -import unicode from "unicode-properties"; import { booleanPrefixes, forbiddenPropertyNames } from "./constants"; export function typeNameStyle(prefix: string, original: string): string { @@ -39,7 +40,7 @@ export function propertyNameStyle(original: string, isBool = false): string { if (words.length === 0) { words = [{ word: "flag", isAcronym: false }]; // @ts-expect-error needs strict type - } else if (!words[0].isAcronym && booleanPrefixes.indexOf(words[0].word) < 0) { + } else if (!words[0].isAcronym && !booleanPrefixes.includes(words[0].word)) { words = [{ word: "is", isAcronym: false }, ...words]; } } @@ -47,7 +48,7 @@ export function propertyNameStyle(original: string, isBool = false): string { // Properties cannot even begin with any of the forbidden names // For example, properies named new* are treated differently by ARC // @ts-expect-error needs strict type - if (words.length > 0 && forbiddenPropertyNames.indexOf(words[0].word) >= 0) { + if (words.length > 0 && forbiddenPropertyNames.includes(words[0].word)) { words = [{ word: "the", isAcronym: false }, ...words]; } @@ -69,7 +70,7 @@ function isStartCharacter(utf16Unit: number): boolean { function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); @@ -81,5 +82,5 @@ export function splitExtension(filename: string): [string, string] { const i = filename.lastIndexOf("."); const extension = i !== -1 ? filename.split(".").pop() : "m"; filename = i !== -1 ? filename.slice(0, i) : filename; - return [filename, extension === undefined ? "m" : extension]; + return [filename, extension ?? "m"]; } diff --git a/packages/quicktype-core/src/language/Php/utils.ts b/packages/quicktype-core/src/language/Php/utils.ts index 2c219178d..2ccb0e228 100644 --- a/packages/quicktype-core/src/language/Php/utils.ts +++ b/packages/quicktype-core/src/language/Php/utils.ts @@ -1,3 +1,5 @@ +import * as _ from "lodash"; + import { allLowerWordStyle, allUpperWordStyle, @@ -12,7 +14,6 @@ import { utf16ConcatMap, utf16LegalizeCharacters } from "../../support/Strings"; -import * as _ from "lodash"; export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); diff --git a/packages/quicktype-core/src/language/Pike/utils.ts b/packages/quicktype-core/src/language/Pike/utils.ts index c672bb1d2..f097ad2c6 100644 --- a/packages/quicktype-core/src/language/Pike/utils.ts +++ b/packages/quicktype-core/src/language/Pike/utils.ts @@ -1,5 +1,5 @@ import { funPrefixNamer } from "../../Naming"; -import { legalizeCharacters, isLetterOrUnderscoreOrDigit, makeNameStyle } from "../../support/Strings"; +import { isLetterOrUnderscoreOrDigit, legalizeCharacters, makeNameStyle } from "../../support/Strings"; const legalizeName = legalizeCharacters(isLetterOrUnderscoreOrDigit); export const enumNamingFunction = funPrefixNamer("enumNamer", makeNameStyle("upper-underscore", legalizeName)); diff --git a/packages/quicktype-core/src/language/Python/utils.ts b/packages/quicktype-core/src/language/Python/utils.ts index 8145ff018..6ffb8c5a2 100644 --- a/packages/quicktype-core/src/language/Python/utils.ts +++ b/packages/quicktype-core/src/language/Python/utils.ts @@ -1,26 +1,26 @@ +import unicode from "unicode-properties"; + import { - splitIntoWords, + allLowerWordStyle, + allUpperWordStyle, combineWords, firstUpperWordStyle, - utf16LegalizeCharacters, - allUpperWordStyle, - allLowerWordStyle, - originalWord + originalWord, + splitIntoWords, + utf16LegalizeCharacters } from "../../support/Strings"; -import unicode from "unicode-properties"; - function isNormalizedStartCharacter3(utf16Unit: number): boolean { // FIXME: add Other_ID_Start - https://docs.python.org/3/reference/lexical_analysis.html#identifiers const category: string = unicode.getCategory(utf16Unit); - return ["Lu", "Ll", "Lt", "Lm", "Lo", "Nl"].indexOf(category) >= 0; + return ["Lu", "Ll", "Lt", "Lm", "Lo", "Nl"].includes(category); } function isNormalizedPartCharacter3(utf16Unit: number): boolean { // FIXME: add Other_ID_Continue - https://docs.python.org/3/reference/lexical_analysis.html#identifiers if (isNormalizedStartCharacter3(utf16Unit)) return true; const category: string = unicode.getCategory(utf16Unit); - return ["Mn", "Mc", "Nd", "Pc"].indexOf(category) >= 0; + return ["Mn", "Mc", "Nd", "Pc"].includes(category); } function isStartCharacter3(utf16Unit: number): boolean { @@ -30,6 +30,7 @@ function isStartCharacter3(utf16Unit: number): boolean { for (let i = 1; i < l; i++) { if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; } + return true; } @@ -39,6 +40,7 @@ function isPartCharacter3(utf16Unit: number): boolean { for (let i = 0; i < l; i++) { if (!isNormalizedPartCharacter3(s.charCodeAt(i))) return false; } + return true; } @@ -62,6 +64,7 @@ function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean) { if (!forceSnakeNameStyle) { return originalWord; } + return uppercase ? allUpperWordStyle : allLowerWordStyle; } diff --git a/packages/quicktype-core/src/language/Ruby/utils.ts b/packages/quicktype-core/src/language/Ruby/utils.ts index 669c0127d..907be72a4 100644 --- a/packages/quicktype-core/src/language/Ruby/utils.ts +++ b/packages/quicktype-core/src/language/Ruby/utils.ts @@ -1,21 +1,21 @@ import unicode from "unicode-properties"; -import * as keywords from "./constants"; - import { - legalizeCharacters, - splitIntoWords, - combineWords, - firstUpperWordStyle, - allUpperWordStyle, allLowerWordStyle, - utf32ConcatMap, - isPrintable, + allUpperWordStyle, + combineWords, escapeNonPrintableMapper, + firstUpperWordStyle, intToHex, - isLetterOrUnderscore + isLetterOrUnderscore, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap } from "../../support/Strings"; +import * as keywords from "./constants"; + export const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); function unicodeEscape(codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; @@ -27,7 +27,7 @@ const isStartCharacter = isLetterOrUnderscore; function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].indexOf(category) >= 0 || isStartCharacter(utf16Unit); + return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); } const legalizeName = legalizeCharacters(isPartCharacter); @@ -36,6 +36,7 @@ export function simpleNameStyle(original: string, uppercase: boolean): string { if (/^[0-9]+$/.test(original)) { original = original + "N"; } + const words = splitIntoWords(original); return combineWords( words, diff --git a/packages/quicktype-core/src/language/Rust/utils.ts b/packages/quicktype-core/src/language/Rust/utils.ts index 4da4582cf..5806f63a3 100644 --- a/packages/quicktype-core/src/language/Rust/utils.ts +++ b/packages/quicktype-core/src/language/Rust/utils.ts @@ -1,26 +1,26 @@ +import { funPrefixNamer } from "../../Naming"; import { - legalizeCharacters, - splitIntoWords, - isLetterOrUnderscoreOrDigit, - combineWords, allLowerWordStyle, + combineWords, + escapeNonPrintableMapper, firstUpperWordStyle, intToHex, - utf32ConcatMap, - escapeNonPrintableMapper, - isPrintable, isAscii, - isLetterOrUnderscore + isLetterOrUnderscore, + isLetterOrUnderscoreOrDigit, + isPrintable, + legalizeCharacters, + splitIntoWords, + utf32ConcatMap } from "../../support/Strings"; -import { funPrefixNamer } from "../../Naming"; type NameToParts = (name: string) => string[]; type PartsToName = (parts: string[]) => string; -type NamingStyle = { +interface NamingStyle { + fromParts: PartsToName; regex: RegExp; toParts: NameToParts; - fromParts: PartsToName; -}; +} export const namingStyles: Record = { snake_case: { @@ -131,6 +131,7 @@ export function getPreferedNamingStyle(namingStyleOccurences: string[], defaultS if (preferedStyles.includes(defaultStyle)) { return defaultStyle; } + return preferedStyles[0]; } @@ -144,9 +145,11 @@ export function nameToNamingStyle(name: string, style: string): string { if (namingStyles[style].regex.test(name)) { return name; } + const fromStyle = listMatchingNamingStyles(name)[0]; if (fromStyle === undefined) { return name; } + return namingStyles[style].fromParts(namingStyles[fromStyle].toParts(name)); } diff --git a/packages/quicktype-core/src/language/Scala3/utils.ts b/packages/quicktype-core/src/language/Scala3/utils.ts index 40358a18e..1de23bcb8 100644 --- a/packages/quicktype-core/src/language/Scala3/utils.ts +++ b/packages/quicktype-core/src/language/Scala3/utils.ts @@ -10,6 +10,7 @@ import { legalizeCharacters, splitIntoWords } from "../../support/Strings"; + import { invalidSymbols, keywords } from "./constants"; /** @@ -61,7 +62,7 @@ export function scalaNameStyle(isUpper: boolean, original: string): string { return "\\u" + intToHex(codePoint, 4); } */ -//const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); +// const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); /* function stringEscape(s: string): string { // "$this" is a template string in Kotlin so we have to escape $ diff --git a/packages/quicktype-core/src/language/Smithy4s/utils.ts b/packages/quicktype-core/src/language/Smithy4s/utils.ts index 6683ac138..7075f6627 100644 --- a/packages/quicktype-core/src/language/Smithy4s/utils.ts +++ b/packages/quicktype-core/src/language/Smithy4s/utils.ts @@ -1,16 +1,18 @@ +import { isDigit } from "unicode-properties"; + import { funPrefixNamer } from "../../Naming"; import { + allLowerWordStyle, + allUpperWordStyle, + combineWords, + firstUpperWordStyle, isLetterOrUnderscore, isNumeric, legalizeCharacters, - splitIntoWords, - combineWords, - firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle + splitIntoWords } from "../../support/Strings"; -import { isDigit } from "unicode-properties"; -import { keywords, invalidSymbols } from "./constants"; + +import { invalidSymbols, keywords } from "./constants"; /** * Check if given parameter name should be wrapped in a backtick diff --git a/packages/quicktype-core/src/language/Swift/utils.ts b/packages/quicktype-core/src/language/Swift/utils.ts index 34d5ace85..ce4e2fa8b 100644 --- a/packages/quicktype-core/src/language/Swift/utils.ts +++ b/packages/quicktype-core/src/language/Swift/utils.ts @@ -1,23 +1,23 @@ -import { ClassProperty } from "../../Type"; -import { Name } from "../../Naming"; +import { DefaultDateTimeRecognizer } from "../../DateTime"; +import { type Name } from "../../Naming"; +import { type ForEachPosition } from "../../Renderer"; import { - legalizeCharacters, + addPrefixIfNecessary, + allLowerWordStyle, + allUpperWordStyle, + combineWords, + escapeNonPrintableMapper, + firstUpperWordStyle, + intToHex, + isDigit, isLetterOrUnderscore, isNumeric, - isDigit, - utf32ConcatMap, - escapeNonPrintableMapper, isPrintable, - intToHex, + legalizeCharacters, splitIntoWords, - combineWords, - firstUpperWordStyle, - allLowerWordStyle, - allUpperWordStyle, - addPrefixIfNecessary + utf32ConcatMap } from "../../support/Strings"; -import { ForEachPosition } from "../../Renderer"; -import { DefaultDateTimeRecognizer } from "../../DateTime"; +import { type ClassProperty } from "../../Type"; export const MAX_SAMELINE_PROPERTIES = 4; @@ -35,14 +35,14 @@ export const MAX_SAMELINE_PROPERTIES = 4; const swiftDateTimeRegex = /^\d+-\d+-\d+T\d+:\d+:\d+([zZ]|[+-]\d+(:\d+)?)$/; export class SwiftDateTimeRecognizer extends DefaultDateTimeRecognizer { - isDateTime(str: string): boolean { - return str.match(swiftDateTimeRegex) !== null; + public isDateTime(str: string): boolean { + return swiftDateTimeRegex.exec(str) !== null; } } export interface SwiftProperty { - name: Name; jsonName: string; + name: Name; parameter: ClassProperty; position: ForEachPosition; } diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts b/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts index 6f274b062..b15b7eb1d 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts @@ -1,6 +1,6 @@ +import { utf16StringEscape } from "../../support/Strings"; import { isES3IdentifierStart } from "../JavaScript/unicodeMaps"; import { legalizeName } from "../JavaScript/utils"; -import { utf16StringEscape } from "../../support/Strings"; export const tsFlowTypeAnnotations = { any: ": any", From 0bec808b7448dcb82cb5a43e628990720e63dcf2 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 5 May 2024 15:55:57 -0700 Subject: [PATCH 76/80] fix dep cycle for CSharp --- .../src/language/CSharp/CSharpRenderer.ts | 11 +++++++++-- .../src/language/CSharp/NewtonSoftCSharpRenderer.ts | 3 ++- .../language/CSharp/SystemTextJsonCSharpRenderer.ts | 3 ++- .../quicktype-core/src/language/CSharp/language.ts | 6 ------ packages/quicktype-core/src/language/CSharp/utils.ts | 6 ++++++ 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts index 7b139b4af..09cfcc3ca 100644 --- a/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts +++ b/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts @@ -12,8 +12,15 @@ import { followTargetType } from "../../Transformers"; import { type ClassProperty, type ClassType, type EnumType, type Type, type UnionType } from "../../Type"; import { directlyReachableSingleNamedType, matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; -import { AccessModifier, type cSharpOptions } from "./language"; -import { csTypeForTransformedStringType, isValueType, namingFunction, namingFunctionKeep, noFollow } from "./utils"; +import { type cSharpOptions } from "./language"; +import { + AccessModifier, + csTypeForTransformedStringType, + isValueType, + namingFunction, + namingFunctionKeep, + noFollow +} from "./utils"; export class CSharpRenderer extends ConvenienceRenderer { public constructor( diff --git a/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts index f34c3053f..4d6b09da6 100644 --- a/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts +++ b/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts @@ -32,8 +32,9 @@ import { ArrayType, type ClassProperty, ClassType, EnumType, type Type, UnionTyp import { nullableFromUnion } from "../../TypeUtils"; import { CSharpRenderer } from "./CSharpRenderer"; -import { AccessModifier, type newtonsoftCSharpOptions } from "./language"; +import { type newtonsoftCSharpOptions } from "./language"; import { + AccessModifier, alwaysApplyTransformation, denseJsonPropertyName, denseNullValueHandlingEnumName, diff --git a/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts index 7d9effc49..77afed6da 100644 --- a/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts +++ b/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts @@ -32,8 +32,9 @@ import { ArrayType, type ClassProperty, ClassType, EnumType, type Type, UnionTyp import { nullableFromUnion } from "../../TypeUtils"; import { CSharpRenderer } from "./CSharpRenderer"; -import { AccessModifier, type systemTextJsonCSharpOptions } from "./language"; +import { type systemTextJsonCSharpOptions } from "./language"; import { + AccessModifier, alwaysApplyTransformation, denseJsonPropertyName, denseNullValueHandlingEnumName, diff --git a/packages/quicktype-core/src/language/CSharp/language.ts b/packages/quicktype-core/src/language/CSharp/language.ts index b706146b5..e2b460582 100644 --- a/packages/quicktype-core/src/language/CSharp/language.ts +++ b/packages/quicktype-core/src/language/CSharp/language.ts @@ -22,12 +22,6 @@ export interface OutputFeatures { helpers: boolean; } -export enum AccessModifier { - None = "None", - Public = "Public", - Internal = "Internal" -} - export type CSharpTypeForAny = "object" | "dynamic"; export const cSharpOptions = { diff --git a/packages/quicktype-core/src/language/CSharp/utils.ts b/packages/quicktype-core/src/language/CSharp/utils.ts index 3b619e672..856de95ca 100644 --- a/packages/quicktype-core/src/language/CSharp/utils.ts +++ b/packages/quicktype-core/src/language/CSharp/utils.ts @@ -17,6 +17,12 @@ import { nullableFromUnion } from "../../TypeUtils"; import { keywords } from "./constants"; +export enum AccessModifier { + None = "None", + Public = "Public", + Internal = "Internal" +} + export function noFollow(t: Type): Type { return t; } From a54d7d5a6c5ed56edce061bf76b810efa9d6d3e5 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 5 May 2024 15:57:37 -0700 Subject: [PATCH 77/80] fix dep cycle for ObjectiveC --- .../src/language/Objective-C/ObjectiveCRenderer.ts | 3 ++- packages/quicktype-core/src/language/Objective-C/language.ts | 3 +-- packages/quicktype-core/src/language/Objective-C/utils.ts | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts index e4bd7517d..faca214c8 100644 --- a/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts +++ b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts @@ -12,8 +12,9 @@ import { ArrayType, type ClassProperty, ClassType, EnumType, MapType, Type, Unio import { isAnyOrNull, matchType, nullableFromUnion } from "../../TypeUtils"; import { forbiddenPropertyNames, keywords } from "./constants"; -import { DEFAULT_CLASS_PREFIX, type MemoryAttribute, type objectiveCOptions } from "./language"; +import { type MemoryAttribute, type objectiveCOptions } from "./language"; import { + DEFAULT_CLASS_PREFIX, forbiddenForEnumCases, propertyNameStyle, splitExtension, diff --git a/packages/quicktype-core/src/language/Objective-C/language.ts b/packages/quicktype-core/src/language/Objective-C/language.ts index 9c4984df6..cb34271f9 100644 --- a/packages/quicktype-core/src/language/Objective-C/language.ts +++ b/packages/quicktype-core/src/language/Objective-C/language.ts @@ -4,6 +4,7 @@ import { TargetLanguage } from "../../TargetLanguage"; import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; import { ObjectiveCRenderer } from "./ObjectiveCRenderer"; +import { DEFAULT_CLASS_PREFIX } from "./utils"; export type MemoryAttribute = "assign" | "strong" | "copy"; export interface OutputFeatures { @@ -11,8 +12,6 @@ export interface OutputFeatures { interface: boolean; } -export const DEFAULT_CLASS_PREFIX = "QT"; - export const objectiveCOptions = { features: new EnumOption("features", "Interface and implementation", [ ["all", { interface: true, implementation: true }], diff --git a/packages/quicktype-core/src/language/Objective-C/utils.ts b/packages/quicktype-core/src/language/Objective-C/utils.ts index 7e83f5610..cdff7db57 100644 --- a/packages/quicktype-core/src/language/Objective-C/utils.ts +++ b/packages/quicktype-core/src/language/Objective-C/utils.ts @@ -12,6 +12,8 @@ import { import { booleanPrefixes, forbiddenPropertyNames } from "./constants"; +export const DEFAULT_CLASS_PREFIX = "QT"; + export function typeNameStyle(prefix: string, original: string): string { const words = splitIntoWords(original); const result = combineWords( From 0f97dc6dcb179e284637c2a9532aa5a223a9f839 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 5 May 2024 15:59:05 -0700 Subject: [PATCH 78/80] fix dep cycle for Ruby --- packages/quicktype-core/src/language/Ruby/RubyRenderer.ts | 4 ++-- packages/quicktype-core/src/language/Ruby/language.ts | 7 +------ packages/quicktype-core/src/language/Ruby/utils.ts | 6 ++++++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts index f02e967cd..081139193 100644 --- a/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts +++ b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts @@ -17,8 +17,8 @@ import { import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; import { globals } from "./constants"; -import { Strictness, type rubyOptions } from "./language"; -import { forbiddenForObjectProperties, memberNameStyle, simpleNameStyle, stringEscape } from "./utils"; +import { type rubyOptions } from "./language"; +import { Strictness, forbiddenForObjectProperties, memberNameStyle, simpleNameStyle, stringEscape } from "./utils"; export class RubyRenderer extends ConvenienceRenderer { public constructor( diff --git a/packages/quicktype-core/src/language/Ruby/language.ts b/packages/quicktype-core/src/language/Ruby/language.ts index d0d40af12..e85598008 100644 --- a/packages/quicktype-core/src/language/Ruby/language.ts +++ b/packages/quicktype-core/src/language/Ruby/language.ts @@ -4,12 +4,7 @@ import { TargetLanguage } from "../../TargetLanguage"; import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; import { RubyRenderer } from "./RubyRenderer"; - -export enum Strictness { - Strict = "Strict::", - Coercible = "Coercible::", - None = "Types::" -} +import { Strictness } from "./utils"; export const rubyOptions = { justTypes: new BooleanOption("just-types", "Plain types only", false), diff --git a/packages/quicktype-core/src/language/Ruby/utils.ts b/packages/quicktype-core/src/language/Ruby/utils.ts index 907be72a4..1b78d957c 100644 --- a/packages/quicktype-core/src/language/Ruby/utils.ts +++ b/packages/quicktype-core/src/language/Ruby/utils.ts @@ -16,6 +16,12 @@ import { import * as keywords from "./constants"; +export enum Strictness { + Strict = "Strict::", + Coercible = "Coercible::", + None = "Types::" +} + export const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); function unicodeEscape(codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; From e8b3dfb2e758cf1a61d6696534189a50cf10a349 Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 5 May 2024 15:59:41 -0700 Subject: [PATCH 79/80] fix dep cycle for Rust --- .../quicktype-core/src/language/Rust/RustRenderer.ts | 4 +++- .../quicktype-core/src/language/Rust/language.ts | 12 +----------- packages/quicktype-core/src/language/Rust/utils.ts | 11 +++++++++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/quicktype-core/src/language/Rust/RustRenderer.ts b/packages/quicktype-core/src/language/Rust/RustRenderer.ts index 79b25acea..6e0a6653f 100644 --- a/packages/quicktype-core/src/language/Rust/RustRenderer.ts +++ b/packages/quicktype-core/src/language/Rust/RustRenderer.ts @@ -13,8 +13,10 @@ import { type ClassType, type EnumType, type Type, UnionType } from "../../Type" import { matchType, nullableFromUnion, removeNullFromUnion } from "../../TypeUtils"; import { keywords } from "./constants"; -import { Density, Visibility, type rustOptions } from "./language"; +import { type rustOptions } from "./language"; import { + Density, + Visibility, camelNamingFunction, getPreferedNamingStyle, listMatchingNamingStyles, diff --git a/packages/quicktype-core/src/language/Rust/language.ts b/packages/quicktype-core/src/language/Rust/language.ts index 0c206884e..2f62883ea 100644 --- a/packages/quicktype-core/src/language/Rust/language.ts +++ b/packages/quicktype-core/src/language/Rust/language.ts @@ -4,17 +4,7 @@ import { TargetLanguage } from "../../TargetLanguage"; import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; import { RustRenderer } from "./RustRenderer"; - -export enum Density { - Normal = "Normal", - Dense = "Dense" -} - -export enum Visibility { - Private = "Private", - Crate = "Crate", - Public = "Public" -} +import { Density, Visibility } from "./utils"; export const rustOptions = { density: new EnumOption("density", "Density", [ diff --git a/packages/quicktype-core/src/language/Rust/utils.ts b/packages/quicktype-core/src/language/Rust/utils.ts index 5806f63a3..1b086f545 100644 --- a/packages/quicktype-core/src/language/Rust/utils.ts +++ b/packages/quicktype-core/src/language/Rust/utils.ts @@ -14,6 +14,17 @@ import { utf32ConcatMap } from "../../support/Strings"; +export enum Density { + Normal = "Normal", + Dense = "Dense" +} + +export enum Visibility { + Private = "Private", + Crate = "Crate", + Public = "Public" +} + type NameToParts = (name: string) => string[]; type PartsToName = (parts: string[]) => string; interface NamingStyle { From a188f7976342e3349226841253caa217165e3b5e Mon Sep 17 00:00:00 2001 From: inferrinizzard Date: Sun, 12 May 2024 15:23:36 -0700 Subject: [PATCH 80/80] :recycle: fix imports --- packages/quicktype-core/src/language/CJSON/language.ts | 1 + packages/quicktype-core/src/language/CPlusPlus/utils.ts | 2 +- packages/quicktype-core/src/language/JSONSchema/language.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/quicktype-core/src/language/CJSON/language.ts b/packages/quicktype-core/src/language/CJSON/language.ts index fdcde98a7..c18c6806a 100644 --- a/packages/quicktype-core/src/language/CJSON/language.ts +++ b/packages/quicktype-core/src/language/CJSON/language.ts @@ -25,6 +25,7 @@ import { type RenderContext } from "../../Renderer"; import { EnumOption, type Option, StringOption, getOptionValues } from "../../RendererOptions"; import { type NamingStyle } from "../../support/Strings"; import { TargetLanguage } from "../../TargetLanguage"; +import { type FixMeOptionsType, type FixMeOptionsAnyType } from "../../types"; import { CJSONRenderer } from "./CJSONRenderer"; diff --git a/packages/quicktype-core/src/language/CPlusPlus/utils.ts b/packages/quicktype-core/src/language/CPlusPlus/utils.ts index f93ce5d54..93c6e75de 100644 --- a/packages/quicktype-core/src/language/CPlusPlus/utils.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/utils.ts @@ -134,7 +134,7 @@ export function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): So return [qualifier, qualified]; } -class WrappingCode { +export class WrappingCode { public constructor( private readonly start: Sourcelike[], private readonly end: Sourcelike[] diff --git a/packages/quicktype-core/src/language/JSONSchema/language.ts b/packages/quicktype-core/src/language/JSONSchema/language.ts index 7ada4a1e0..7374537a1 100644 --- a/packages/quicktype-core/src/language/JSONSchema/language.ts +++ b/packages/quicktype-core/src/language/JSONSchema/language.ts @@ -2,7 +2,7 @@ import { type RenderContext } from "../../Renderer"; import { type Option } from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; import { type StringTypeMapping, getNoStringTypeMapping } from "../../TypeBuilder"; -import { type FixMeOptionsAnyType } from "../../types"; +import { type FixMeOptionsAnyType, type FixMeOptionsType } from "../../types"; import { JSONSchemaRenderer } from "./JSONSchemaRenderer";