diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 135b0997..00000000 --- a/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -dist -node_modules -packages/*/dist -packages/*/node_modules -test/runs -test/input - -license diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index f35b5c03..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "overrides": [ - { - "extends": ["canonical/json"], - "files": "*.json" - }, - { - "extends": [ - "eslint:recommended", - "canonical/typescript", - "canonical/typescript-type-checking", - "plugin:import/errors", - "plugin:import/warnings", - "plugin:import/typescript" - ], - "plugins": ["canonical"], - "parserOptions": { - "tsconfigRootDir": "./", - "project": ["./tsconfig.json", "./packages/*/tsconfig.json"] - }, - "settings": { - "import/resolver": { - "typescript": true, - "node": true - } - }, - "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", - - "sort-imports": [ - "error", - { - "ignoreDeclarationSort": true - } - ], - "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"], - "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }], - "@typescript-eslint/explicit-function-return-type": "warn", - "@typescript-eslint/indent": "off", - "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true }], - "@typescript-eslint/member-delimiter-style": "off", - "@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", - "@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/unbound-method": "warn", - "@typescript-eslint/unified-signatures": "error" - }, - "overrides": [ - { - "files": "*.d.ts", - "rules": { - "no-var": "off" - } - } - ], - "files": "*.ts" - } - ], - "root": true -} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 24d3c3b5..00000000 --- a/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -test/runs -test/inputs diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 99478487..00000000 --- a/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -{ "tabWidth": 4, "printWidth": 120, "trailingComma": "none", "arrowParens": "avoid", "quoteProps": "consistent" } diff --git a/.vscode/settings.json b/.vscode/settings.json index f5759625..b666505d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,7 +23,7 @@ }, "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.defaultFormatter": "biomejs.biome", "editor.wordWrap": "on", "editor.insertSpaces": true, "editor.tabSize": 4, diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..a1af651f --- /dev/null +++ b/biome.json @@ -0,0 +1,16 @@ +{ + "files": { + "ignore": [ + "test/runs", + "test/inputs", + "dist", + "node_modules", + "packages/*/dist", + "packages/*/node_modules" + ] + }, + "formatter": { + "indentStyle": "space", + "indentWidth": 4 + } +} diff --git a/package-lock.json b/package-lock.json index b362c04c..b6ddb039 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "quicktype", - "version": "23.1.0", + "version": "23.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "quicktype", - "version": "23.1.0", + "version": "23.2.0", "license": "Apache-2.0", "workspaces": [ "./packages/quicktype-core", @@ -30,12 +30,13 @@ "readable-stream": "^4.5.2", "stream-json": "1.8.0", "string-to-stream": "^3.0.1", - "typescript": "4.9.5" + "typescript": "~5.8.3" }, "bin": { "quicktype": "dist/index.js" }, "devDependencies": { + "@biomejs/biome": "^1.9.4", "@tsconfig/node18": "^1.0.1", "@types/command-line-args": "^5.2.0", "@types/command-line-usage": "^5.0.4", @@ -51,16 +52,7 @@ "ajv": "^5.5.2", "deep-equal": "^2.2.3", "esbuild": "^0.20.2", - "eslint": "^8.57.0", - "eslint-config-canonical": "^41.1.7", - "eslint-config-prettier": "^6.10.0", - "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", - "eslint-plugin-prettier": "^4.2.1", "exit": "^0.1.2", - "prettier": "^3.2.5", "promise-timeout": "^1.3.0", "semver": "^7.5.4", "shelljs": "^0.8.5", @@ -97,567 +89,175 @@ "node": ">=0.10.0" } }, - "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/@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.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "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": { - "node-fetch": "^2.6.1" - }, - "engines": { - "node": ">=14" - } - }, - "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": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", - "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", - "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.24.5", - "@babel/helpers": "^7.24.5", - "@babel/parser": "^7.24.5", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.5", - "@babel/types": "^7.24.5", - "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/@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/@babel/eslint-parser": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.5.tgz", - "integrity": "sha512-gsUcqS/fPlgAw1kOtpss7uhY6E9SFFANQ6EFX5GTvzUwaV0+sGaZWk6xq22MOdeT9wfxyokW3ceCUvOiRtZciQ==", - "dev": true, - "dependencies": { - "@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 || ^9.0.0" - } - }, - "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/@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/@babel/eslint-plugin": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.24.5.tgz", - "integrity": "sha512-5n3K9Zv13VOa9SG2ZiX0WV7A0ddApRn6vsV8zBojCsxnCbYKLjCDvzDfVxS7C4STmjQDOXU1uk/ppxxDTC860w==", - "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 || ^9.0.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", - "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.5", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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/@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": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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": { - "@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/@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": { - "yallist": "^3.0.2" - } - }, - "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/@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/@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": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", - "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.24.3", - "@babel/helper-simple-access": "^7.24.5", - "@babel/helper-split-export-declaration": "^7.24.5", - "@babel/helper-validator-identifier": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", - "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", - "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", - "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", - "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "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": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", - "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.5", - "@babel/types": "^7.24.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", - "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", - "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "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": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "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": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "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": { - "@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": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", - "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.5.tgz", - "integrity": "sha512-GWO0mgzNMLWaSYM4z4NVIuY0Cd1fl8cPnuetuddu5w/qGuvt5Y7oUi/kvvQGK9xgOkFJDQX2heIvTRn/OQ1XTg==", - "dev": true, - "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", - "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.5", - "@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.24.5", - "@babel/parser": "^7.24.5", - "@babel/types": "^7.24.5", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "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": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", - "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.24.1", - "@babel/helper-validator-identifier": "^7.24.5", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "dev": true, "license": "MIT" }, + "node_modules/@biomejs/biome": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz", + "integrity": "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==", + "dev": true, + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.9.4", + "@biomejs/cli-darwin-x64": "1.9.4", + "@biomejs/cli-linux-arm64": "1.9.4", + "@biomejs/cli-linux-arm64-musl": "1.9.4", + "@biomejs/cli-linux-x64": "1.9.4", + "@biomejs/cli-linux-x64-musl": "1.9.4", + "@biomejs/cli-win32-arm64": "1.9.4", + "@biomejs/cli-win32-x64": "1.9.4" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz", + "integrity": "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz", + "integrity": "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz", + "integrity": "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz", + "integrity": "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz", + "integrity": "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz", + "integrity": "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz", + "integrity": "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz", + "integrity": "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "license": "MIT", @@ -668,20 +268,6 @@ "node": ">=12" } }, - "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": { - "comment-parser": "1.4.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@esbuild/win32-x64": { "version": "0.20.2", "cpu": [ @@ -794,92 +380,6 @@ "version": "2.2.3", "license": "MIT" }, - "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": { - "@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/@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": { - "@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" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "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, - "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/@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, - "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-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/@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/@humanwhocodes/config-array": { "version": "0.11.14", "dev": true, @@ -1007,30 +507,6 @@ "node": ">=8" } }, - "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": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", "license": "MIT", @@ -1038,15 +514,6 @@ "node": ">=6.0.0" } }, - "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.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "license": "MIT" @@ -1091,66 +558,6 @@ "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.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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": { - "eslint-scope": "5.1.1" - } - }, - "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": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "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.0" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -1183,63 +590,6 @@ "node": ">= 8" } }, - "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": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2" - } - }, - "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/@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": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "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/@peculiar/webcrypto": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.6.tgz", - "integrity": "sha512-YBcMfqNSwn3SujUJvAaySy5tlYbYm6tVt9SKoXu8BaTdKGROiJDgPR3TXpZdAKUfklzm3lRapJEAltiMQtBgZg==", - "dev": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2", - "webcrypto-core": "^1.7.9" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "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/@pkgjs/parseargs": { "version": "0.11.0", "dev": true, @@ -1249,30 +599,6 @@ "node": ">=14" } }, - "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, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "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/@rushstack/eslint-patch": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz", - "integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==", - "dev": true - }, "node_modules/@tootallnate/once": { "version": "1.1.2", "dev": true, @@ -1346,12 +672,6 @@ "version": "7.0.15", "license": "MIT" }, - "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.17.0", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", @@ -1383,12 +703,6 @@ "@types/node": "*" } }, - "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", "dev": true, @@ -1459,15 +773,6 @@ "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", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "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", @@ -1503,162 +808,6 @@ } } }, - "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": { - "@typescript-eslint/utils": "5.62.0" - }, - "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/@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": { - "@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/@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": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "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": { - "@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/@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": { - "@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/@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, - "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/@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": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "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/@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": { - "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/@typescript-eslint/parser": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", @@ -2006,44 +1155,6 @@ "node": ">= 6" } }, - "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/@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/@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/abort-controller": { "version": "3.0.0", "license": "MIT", @@ -2139,28 +1250,10 @@ "node": ">= 8" } }, - "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/arg": { "version": "4.1.3", "license": "MIT" }, - "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": { - "dequal": "^2.0.3" - } - }, "node_modules/array-back": { "version": "3.1.0", "license": "MIT", @@ -2184,26 +1277,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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": { - "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/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -2213,182 +1286,6 @@ "node": ">=8" } }, - "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": { - "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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": { - "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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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.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/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": { - "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/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": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "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/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": { - "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/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/asn1js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", - "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", - "dev": true, - "dependencies": { - "pvtsutils": "^1.3.2", - "pvutils": "^1.1.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "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": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "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/asynckit": { "version": "0.4.0", "dev": true, @@ -2408,24 +1305,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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, - "engines": { - "node": ">=4" - } - }, - "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": { - "dequal": "^2.0.3" - } - }, "node_modules/azure-devops-node-api": { "version": "12.5.0", "dev": true, @@ -2522,12 +1401,6 @@ "dev": true, "license": "ISC" }, - "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/brace-expansion": { "version": "1.1.11", "license": "MIT", @@ -2570,38 +1443,6 @@ "dev": true, "license": "ISC" }, - "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": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, "node_modules/buffer": { "version": "6.0.3", "funding": [ @@ -2645,18 +1486,6 @@ "dev": true, "license": "MIT" }, - "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": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, "node_modules/c8": { "version": "9.1.0", "dev": true, @@ -2735,26 +1564,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001614", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz", - "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==", - "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", "license": "MIT", @@ -2822,12 +1631,6 @@ "node": ">=8" } }, - "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/cheerio": { "version": "1.0.0-rc.12", "dev": true, @@ -2893,33 +1696,6 @@ "license": "ISC", "optional": true }, - "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": ">=8" - } - }, - "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": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/cliui": { "version": "8.0.1", "license": "ISC", @@ -3021,15 +1797,6 @@ "node": ">=12.17" } }, - "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", "license": "MIT" @@ -3067,66 +1834,10 @@ "dev": true, "license": "MIT" }, - "node_modules/core-js-pure": { - "version": "3.37.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.0.tgz", - "integrity": "sha512-d3BrpyFr5eD4KcbRvQ3FTUx/KWmaDesr7+a3+1+P46IUnNoEt+oiLijPINZMEon7w9oGkIINWxrBAU9DEciwFQ==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "license": "MIT" }, - "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": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "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 - }, - "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": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "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": { - "lodash.get": "^4.3.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/create-require": { "version": "1.1.1", "license": "MIT" @@ -3177,69 +1888,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "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": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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", "dev": true, @@ -3372,15 +2020,6 @@ "node": ">=0.4.0" } }, - "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/detect-libc": { "version": "2.0.3", "dev": true, @@ -3471,15 +2110,6 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "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/duplexer2": { "version": "0.1.4", "dev": true, @@ -3507,12 +2137,6 @@ "dev": true, "license": "MIT" }, - "node_modules/electron-to-chromium": { - "version": "1.4.751", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz", - "integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==", - "dev": true - }, "node_modules/emoji-regex": { "version": "8.0.0", "license": "MIT" @@ -3533,18 +2157,6 @@ "once": "^1.4.0" } }, - "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", "dev": true, @@ -3568,75 +2180,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "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.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "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.8", - "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.6", - "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", "dev": true, @@ -3680,83 +2223,6 @@ "dev": true, "license": "MIT" }, - "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "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/esbuild": { "version": "0.20.2", "dev": true, @@ -3938,1261 +2404,6 @@ "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.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz", - "integrity": "sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ==", - "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.15.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.15.1.tgz", - "integrity": "sha512-PVFrqIJa8BbM/e828RSn0SwB/Z5ye+2LDuy2XqG6AymNgPsfApRRcznsbxP7VrjdLEU4Nb+g9n/d6opyp0jp9A==", - "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.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.3.tgz", - "integrity": "sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==", - "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.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", - "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.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.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.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", - "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.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "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.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" - }, - "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.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.8.0", - "eslint-visitor-keys": "^3.4.3" - }, - "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.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "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.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-1.14.0.tgz", - "integrity": "sha512-ESUpgYPOcAYQO9czugcX5OqRvn/ydDVwGCPXY4YjPqc09rHaUVUA6IE6HLQys4rXk/S+qx3EwTd1wHCwam/OWQ==", - "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", "dev": true, @@ -5208,33 +2419,6 @@ "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", "dev": true, @@ -5337,12 +2521,6 @@ "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", "dev": true, @@ -5418,18 +2596,6 @@ "node": ">=6" } }, - "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/falafel": { "version": "2.2.5", "dev": true, @@ -5458,23 +2624,11 @@ "dev": true, "license": "MIT" }, - "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", "dev": true, "license": "MIT" }, - "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", @@ -5501,42 +2655,6 @@ "dev": true, "license": "MIT" }, - "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", "dev": true, @@ -5680,24 +2798,6 @@ "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", "dev": true, @@ -5706,15 +2806,6 @@ "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", "license": "ISC", @@ -5740,53 +2831,6 @@ "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/github-from-package": { "version": "0.0.0", "dev": true, @@ -5836,22 +2880,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "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", @@ -5888,12 +2916,6 @@ "dev": true, "license": "ISC" }, - "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", "dev": true, @@ -5906,385 +2928,6 @@ "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": { "version": "1.0.3", "dev": true, @@ -6494,18 +3137,6 @@ "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", "dev": true, @@ -6514,15 +3145,6 @@ "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", "license": "ISC", @@ -6591,27 +3213,6 @@ "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", "dev": true, @@ -6649,33 +3250,6 @@ "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", "dev": true, @@ -6699,21 +3273,6 @@ "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", "dev": true, @@ -6736,18 +3295,6 @@ "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", "license": "MIT", @@ -6755,31 +3302,6 @@ "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", "dev": true, @@ -6791,15 +3313,6 @@ "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", "dev": true, @@ -6808,18 +3321,6 @@ "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", "dev": true, @@ -6842,16 +3343,6 @@ "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", "dev": true, @@ -6868,16 +3359,6 @@ "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", "dev": true, @@ -6951,21 +3432,6 @@ "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-unicode-supported": { "version": "0.1.0", "dev": true, @@ -6989,18 +3455,6 @@ "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", "dev": true, @@ -7022,15 +3476,6 @@ "dev": true, "license": "ISC" }, - "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/istanbul-lib-coverage": { "version": "3.2.2", "dev": true, @@ -7087,19 +3532,6 @@ "version": "1.1.3", "license": "MIT" }, - "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/jackspeak": { "version": "2.3.6", "dev": true, @@ -7117,84 +3549,15 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "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": "3.7.7", "license": "BSD-3-Clause" }, - "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/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", "dev": true, "license": "MIT" }, - "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", "dev": true, @@ -7205,56 +3568,11 @@ "dev": true, "license": "MIT" }, - "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", "dev": true, "license": "MIT" }, - "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/jszip": { "version": "3.10.1", "dev": true, @@ -7299,24 +3617,6 @@ "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/leven": { "version": "3.1.0", "dev": true, @@ -7345,12 +3645,6 @@ "immediate": "~3.0.5" } }, - "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/linkify-it": { "version": "3.0.3", "dev": true, @@ -7385,29 +3679,11 @@ "version": "4.3.0", "license": "MIT" }, - "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", "dev": true, "license": "MIT" }, - "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/log-symbols": { "version": "4.1.0", "dev": true, @@ -7423,27 +3699,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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", "dev": true, @@ -7544,29 +3799,6 @@ "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", @@ -7622,15 +3854,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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", "license": "ISC", @@ -7885,12 +4108,6 @@ "dev": true, "license": "MIT" }, - "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-abi": { "version": "3.57.0", "dev": true, @@ -7935,39 +4152,6 @@ "node": ">=10.12.0" } }, - "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/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/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": "3.0.0", "dev": true, @@ -7987,24 +4171,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "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", "dev": true, @@ -8054,86 +4220,6 @@ "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", "license": "ISC", @@ -8185,15 +4271,6 @@ "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", "license": "(MIT AND Zlib)" @@ -8209,24 +4286,6 @@ "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/parse-semver": { "version": "1.1.1", "dev": true, @@ -8335,12 +4394,6 @@ "dev": true, "license": "MIT" }, - "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", "dev": true, @@ -8352,18 +4405,6 @@ "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", "license": "MIT", @@ -8413,32 +4454,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "3.2.5", - "dev": true, - "license": "MIT", - "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", "license": "MIT", @@ -8455,26 +4470,6 @@ "dev": true, "license": "MIT" }, - "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/pump": { "version": "3.0.0", "dev": true, @@ -8493,30 +4488,6 @@ "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/qs": { "version": "6.12.1", "dev": true, @@ -8579,22 +4550,6 @@ "quote-stream": "bin/cmd.js" } }, - "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/randombytes": { "version": "2.1.0", "dev": true, @@ -8627,12 +4582,6 @@ "node": ">=0.10.0" } }, - "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": { "version": "1.0.7", "dev": true, @@ -8644,108 +4593,6 @@ "node": ">=0.8" } }, - "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", "license": "MIT", @@ -8796,41 +4643,6 @@ "node": ">=8.10.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/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/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", "dev": true, @@ -8841,67 +4653,6 @@ "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", "dev": true, @@ -8919,54 +4670,6 @@ "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", "license": "MIT", @@ -8974,15 +4677,6 @@ "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", @@ -9008,15 +4702,6 @@ "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", "dev": true, @@ -9040,20 +4725,6 @@ "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", "dev": true, @@ -9076,51 +4747,10 @@ "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", "license": "MIT" }, - "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", @@ -9138,17 +4768,6 @@ "dev": true, "license": "ISC" }, - "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.6.0", "dev": true, @@ -9163,12 +4782,6 @@ "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/serialize-javascript": { "version": "6.0.0", "dev": true, @@ -9338,52 +4951,11 @@ "version": "0.6.1", "dev": true, "license": "BSD-3-Clause", + "optional": 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/static-eval": { "version": "2.1.1", "dev": true, @@ -9498,15 +5070,6 @@ "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", "license": "MIT", @@ -9514,18 +5077,6 @@ "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", "license": "MIT", @@ -9571,81 +5122,6 @@ "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", "license": "MIT", @@ -9668,27 +5144,6 @@ "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", "dev": true, @@ -9723,24 +5178,6 @@ "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", "license": "MIT", @@ -9869,12 +5306,6 @@ "version": "1.0.2", "license": "MIT" }, - "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/tmp": { "version": "0.2.3", "dev": true, @@ -9883,15 +5314,6 @@ "node": ">=14.14" } }, - "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", "dev": true, @@ -9959,59 +5381,6 @@ } } }, - "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", - "dev": true, - "license": "0BSD" - }, "node_modules/tunnel": { "version": "0.0.6", "dev": true, @@ -10054,79 +5423,6 @@ "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/typed-rest-client": { "version": "1.8.11", "dev": true, @@ -10143,14 +5439,16 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "4.9.5", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/typical": { @@ -10165,21 +5463,6 @@ "dev": true, "license": "MIT" }, - "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/underscore": { "version": "1.13.6", "dev": true, @@ -10223,60 +5506,6 @@ "dev": true, "license": "MIT" }, - "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/unixify/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/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", "dev": true, @@ -10294,12 +5523,6 @@ "dev": true, "license": "MIT" }, - "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", "license": "MIT" @@ -10330,77 +5553,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "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/vlq": { "version": "0.2.3", "dev": true, "license": "MIT" }, - "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", "dev": true, @@ -10416,34 +5573,6 @@ "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.9", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.9.tgz", - "integrity": "sha512-FE+a4PPkOmBbgNDIyRmcHhgXn+2ClRl3JzJdDu/P4+B8y81LqKe6RAsI9b3lAOHe1T1BMkSjsRHTYRikImZnVA==", - "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", "license": "BSD-2-Clause" @@ -10489,38 +5618,6 @@ "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", "dev": true, @@ -10661,28 +5758,6 @@ "version": "1.0.2", "license": "ISC" }, - "node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", - "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/xml2js": { "version": "0.5.0", "dev": true, @@ -10703,15 +5778,6 @@ "node": ">=4.0" } }, - "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/xtend": { "version": "4.0.2", "dev": true, @@ -10742,23 +5808,6 @@ "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", "license": "MIT", @@ -10860,7 +5909,7 @@ "@types/unicode-properties": "^1.3.0", "@types/urijs": "^1.19.25", "@types/wordwrap": "^1.0.3", - "typescript": "4.9.5" + "typescript": "~5.8.3" } }, "packages/quicktype-core/node_modules/pluralize": { @@ -10881,7 +5930,7 @@ "devDependencies": { "@types/graphql": "^0.11.7", "@types/node": "18.19.31", - "typescript": "4.9.5" + "typescript": "~5.8.3" } }, "packages/quicktype-typescript-input": { @@ -10958,6 +6007,19 @@ "util-deprecate": "~1.0.1" } }, + "packages/quicktype-typescript-input/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "packages/quicktype-typescript-input/node_modules/yaml": { "version": "1.10.2", "license": "ISC", @@ -10983,7 +6045,7 @@ "node-persist": "^4.0.1", "quicktype-core": "file:../quicktype-core", "quicktype-typescript-input": "file:../quicktype-typescript-input", - "typescript": "^5.3.3", + "typescript": "~5.8.3", "unicode-properties": "github:quicktype/unicode-properties#dist" }, "engines": { @@ -11204,18 +6266,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/quicktype-vscode/node_modules/typescript": { - "version": "5.4.5", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "packages/quicktype-vscode/node_modules/unicode-properties": { "version": "1.1.0", "resolved": "git+ssh://git@github.com/quicktype/unicode-properties.git#d5fddfea1ef9d05c6479a979e225476063e13f52", diff --git a/package.json b/package.json index c3bf3c39..7f2c3bc8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "quicktype", - "version": "23.1.0", + "version": "23.2.0", "license": "Apache-2.0", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -40,9 +40,10 @@ "readable-stream": "^4.5.2", "stream-json": "1.8.0", "string-to-stream": "^3.0.1", - "typescript": "4.9.5" + "typescript": "~5.8.3" }, "devDependencies": { + "@biomejs/biome": "^1.9.4", "@tsconfig/node18": "^1.0.1", "@types/command-line-args": "^5.2.0", "@types/command-line-usage": "^5.0.4", @@ -58,24 +59,13 @@ "ajv": "^5.5.2", "deep-equal": "^2.2.3", "esbuild": "^0.20.2", - "eslint": "^8.57.0", - "eslint-config-canonical": "^41.1.7", - "eslint-config-prettier": "^6.10.0", - "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", - "eslint-plugin-prettier": "^4.2.1", "exit": "^0.1.2", - "prettier": "^3.2.5", "promise-timeout": "^1.3.0", "semver": "^7.5.4", "shelljs": "^0.8.5", "ts-node": "^10.9.2", "watch": "^1.0.2" }, - "files": [ - "dist" - ], + "files": ["dist"], "bin": "dist/index.js" } diff --git a/packages/quicktype-core/package.json b/packages/quicktype-core/package.json index 580100e8..6a66b53d 100644 --- a/packages/quicktype-core/package.json +++ b/packages/quicktype-core/package.json @@ -36,11 +36,9 @@ "@types/unicode-properties": "^1.3.0", "@types/urijs": "^1.19.25", "@types/wordwrap": "^1.0.3", - "typescript": "4.9.5" + "typescript": "~5.8.3" }, - "files": [ - "dist" - ], + "files": ["dist"], "browser": { "fs": false } diff --git a/packages/quicktype-core/src/Annotation.ts b/packages/quicktype-core/src/Annotation.ts index 1b3a937b..61431cde 100644 --- a/packages/quicktype-core/src/Annotation.ts +++ b/packages/quicktype-core/src/Annotation.ts @@ -8,8 +8,8 @@ export class IssueAnnotationData extends AnnotationData { } 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 ff4797ff..41ae7e4d 100644 --- a/packages/quicktype-core/src/ConvenienceRenderer.ts +++ b/packages/quicktype-core/src/ConvenienceRenderer.ts @@ -6,22 +6,60 @@ import { mapSome, mapSortBy, setFilter, - setUnion + setUnion, } from "collection-utils"; import _wordwrap from "wordwrap"; -import { enumCaseNames, getAccessorName, objectPropertyNames, unionMemberName } from "./attributes/AccessorNames"; -import { descriptionTypeAttributeKind, propertyDescriptionsTypeAttributeKind } from "./attributes/Description"; +import { + enumCaseNames, + getAccessorName, + objectPropertyNames, + unionMemberName, +} from "./attributes/AccessorNames"; +import { + descriptionTypeAttributeKind, + propertyDescriptionsTypeAttributeKind, +} from "./attributes/Description"; 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 { + 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 Transformation, followTargetType, transformationForType } from "./Transformers"; +import type { TargetLanguage } from "./TargetLanguage"; +import { + type Transformation, + followTargetType, + transformationForType, +} from "./Transformers"; import { type ClassProperty, ClassType, @@ -30,10 +68,15 @@ import { ObjectType, type Type, type TypeKind, - UnionType + UnionType, } from "./Type"; import { TypeAttributeStoreView } from "./Type/TypeGraph"; -import { isNamedType, matchTypeExhaustive, nullableFromUnion, separateNamedTypes } from "./Type/TypeUtils"; +import { + isNamedType, + matchTypeExhaustive, + nullableFromUnion, + separateNamedTypes, +} from "./Type/TypeUtils"; const wordWrap: (s: string) => string = _wordwrap(90); @@ -50,13 +93,15 @@ 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; return wordWrap(description) .split("\n") - .map(l => l.trim()); + .map((l) => l.trim()); } export interface ForbiddenWordsInfo { @@ -65,9 +110,15 @@ export interface ForbiddenWordsInfo { } const assignedNameAttributeKind = new TypeAttributeKind("assignedName"); -const assignedPropertyNamesAttributeKind = new TypeAttributeKind>("assignedPropertyNames"); -const assignedMemberNamesAttributeKind = new TypeAttributeKind>("assignedMemberNames"); -const assignedCaseNamesAttributeKind = new TypeAttributeKind>("assignedCaseNames"); +const assignedPropertyNamesAttributeKind = new TypeAttributeKind< + ReadonlyMap +>("assignedPropertyNames"); +const assignedMemberNamesAttributeKind = new TypeAttributeKind< + ReadonlyMap +>("assignedMemberNames"); +const assignedCaseNamesAttributeKind = new TypeAttributeKind< + ReadonlyMap +>("assignedCaseNames"); export abstract class ConvenienceRenderer extends Renderer { private _globalForbiddenNamespace: Namespace | undefined; @@ -78,11 +129,17 @@ export abstract class ConvenienceRenderer extends Renderer { private _nameStoreView: TypeAttributeStoreView | undefined; - private _propertyNamesStoreView: TypeAttributeStoreView> | undefined; + private _propertyNamesStoreView: + | TypeAttributeStoreView> + | undefined; - private _memberNamesStoreView: TypeAttributeStoreView> | undefined; + private _memberNamesStoreView: + | TypeAttributeStoreView> + | undefined; - private _caseNamesStoreView: TypeAttributeStoreView> | undefined; + private _caseNamesStoreView: + | TypeAttributeStoreView> + | undefined; private _namesForTransformations: Map | undefined; @@ -114,7 +171,10 @@ export abstract class ConvenienceRenderer extends Renderer { private _alphabetizeProperties = false; - public constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + ) { super(targetLanguage, renderContext); } @@ -143,33 +203,54 @@ 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 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; } @@ -194,7 +275,9 @@ export abstract class ConvenienceRenderer extends Renderer { } protected canBeForwardDeclared(_t: Type): boolean { - return panic("If needsTypeDeclarationBeforeUse returns true, canBeForwardDeclared must be implemented"); + return panic( + "If needsTypeDeclarationBeforeUse returns true, canBeForwardDeclared must be implemented", + ); } protected unionNeedsName(u: UnionType): boolean { @@ -210,29 +293,41 @@ export abstract class ConvenienceRenderer extends Renderer { } protected descriptionForType(t: Type): string[] | undefined { - let description = this.typeGraph.attributeStore.tryGet(descriptionTypeAttributeKind, t); + const description = this.typeGraph.attributeStore.tryGet( + descriptionTypeAttributeKind, + t, + ); return splitDescription(description); } - protected descriptionForClassProperty(o: ObjectType, name: string): string[] | undefined { - const descriptions = this.typeGraph.attributeStore.tryGet(propertyDescriptionsTypeAttributeKind, o); + 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 { - this._nameStoreView = new TypeAttributeStoreView(this.typeGraph.attributeStore, assignedNameAttributeKind); + 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(); @@ -240,13 +335,25 @@ export abstract class ConvenienceRenderer extends Renderer { this._unionMemberNamer = this.makeUnionMemberNamer(); this._enumCaseNamer = this.makeEnumCaseNamer(); - this._globalForbiddenNamespace = keywordNamespace("forbidden", this.forbiddenNamesForGlobalNamespace()); + this._globalForbiddenNamespace = keywordNamespace( + "forbidden", + this.forbiddenNamesForGlobalNamespace(), + ); this._otherForbiddenNamespaces = new Map(); - this._globalNamespace = new Namespace("global", undefined, [this._globalForbiddenNamespace], []); - const { objects, enums, unions } = this.typeGraph.allNamedTypesSeparated(); - const namedUnions = setFilter(unions, u => this.unionNeedsName(u)); + this._globalNamespace = new Namespace( + "global", + undefined, + [this._globalForbiddenNamespace], + [], + ); + const { objects, enums, unions } = + this.typeGraph.allNamedTypesSeparated(); + const namedUnions = setFilter(unions, (u) => this.unionNeedsName(u)); for (const [name, t] of this.topLevels) { - this.nameStoreView.setForTopLevel(name, this.addNameForTopLevel(t, name)); + this.nameStoreView.setForTopLevel( + name, + this.addNameForTopLevel(t, name), + ); } for (const o of objects) { @@ -270,7 +377,7 @@ export abstract class ConvenienceRenderer extends Renderer { return setUnion( [this._globalForbiddenNamespace, this._globalNamespace], - this._otherForbiddenNamespaces.values() + this._otherForbiddenNamespaces.values(), ); } @@ -281,8 +388,16 @@ export abstract class ConvenienceRenderer extends Renderer { } } - protected makeNameForTopLevel(_t: Type, givenName: string, _maybeNamedType: Type | undefined): Name { - return new SimpleName([givenName], defined(this._namedTypeNamer), topLevelNameOrder); + 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 { @@ -302,14 +417,24 @@ 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 { - return this.makeNameForType(t, defined(this._namedTypeNamer), givenNameOrder, inferredNameOrder); + return this.makeNameForType( + t, + defined(this._namedTypeNamer), + givenNameOrder, + inferredNameOrder, + ); } private addNameForNamedType(type: Type): Name { @@ -346,10 +471,13 @@ export abstract class ConvenienceRenderer extends Renderer { 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)); + const name = this.makeNameForTransformation( + xf, + this.nameStoreView.tryGet(xf.targetType), + ); if (name === undefined) return; this.globalNamespace.add(name); @@ -358,8 +486,11 @@ export abstract class ConvenienceRenderer extends Renderer { 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) { @@ -370,15 +501,21 @@ export abstract class ConvenienceRenderer extends Renderer { } } - let namespace = defined(this._otherForbiddenNamespaces).get(namespaceName); + 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); + this._otherForbiddenNamespaces = defined( + this._otherForbiddenNamespaces, + ).set(namespaceName, namespace); } let forbiddenNamespaces = new Set(); if (info.includeGlobalForbidden) { - forbiddenNamespaces = forbiddenNamespaces.add(defined(this._globalForbiddenNamespace)); + forbiddenNamespaces = forbiddenNamespaces.add( + defined(this._globalForbiddenNamespace), + ); } if (namespace !== undefined) { @@ -393,7 +530,7 @@ export abstract class ConvenienceRenderer extends Renderer { _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; @@ -407,8 +544,14 @@ export abstract class ConvenienceRenderer extends Renderer { // maybe we'll need global properties for some weird language at // some point. const alternative = `${o.getCombinedName()}_${jsonName}`; - const order = assignedName === undefined ? classPropertyNameOrder : assignedClassPropertyNameOrder; - const names = assignedName === undefined ? [jsonName, alternative] : [assignedName]; + const order = + assignedName === undefined + ? classPropertyNameOrder + : assignedClassPropertyNameOrder; + const names = + assignedName === undefined + ? [jsonName, alternative] + : [assignedName]; return new SimpleName(names, namer, order); } @@ -417,36 +560,57 @@ export abstract class ConvenienceRenderer extends Renderer { _className: Name, _p: ClassProperty, _jsonName: string, - _name: Name + _name: Name, ): Name[] { return []; } private addPropertyNames(o: ObjectType, className: Name): void { - const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( - this.forbiddenForObjectProperties(o, className), - "forbidden-for-properties" - ); + const { forbiddenNames, forbiddenNamespaces } = + this.processForbiddenWordsInfo( + this.forbiddenForObjectProperties(o, className), + "forbidden-for-properties", + ); let ns: Namespace | undefined; const accessorNames = objectPropertyNames(o, this.targetLanguage.name); const names = mapFilterMap(o.getSortedProperties(), (p, jsonName) => { - const [assignedName, isFixed] = getAccessorName(accessorNames, jsonName); + const [assignedName, isFixed] = getAccessorName( + accessorNames, + jsonName, + ); let name: Name | undefined; if (isFixed) { name = new FixedName(defined(assignedName)); } else { - name = this.makeNameForProperty(o, className, p, jsonName, assignedName); + 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 = new Namespace( + o.getCombinedName(), + this.globalNamespace, + forbiddenNamespaces, + forbiddenNames, + ); } ns.add(name); - for (const depName of this.makePropertyDependencyNames(o, className, p, jsonName, name)) { + for (const depName of this.makePropertyDependencyNames( + o, + className, + p, + jsonName, + name, + )) { ns.add(depName); } @@ -455,37 +619,59 @@ export abstract class ConvenienceRenderer extends Renderer { defined(this._propertyNamesStoreView).set(o, names); } - protected makeNameForUnionMember(u: UnionType, unionName: Name, t: Type): Name { - const [assignedName, isFixed] = unionMemberName(u, t, this.targetLanguage.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); - }); + 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 { const memberNamer = this._unionMemberNamer; if (memberNamer === null) return; - const { forbiddenNames, forbiddenNamespaces } = this.processForbiddenWordsInfo( - this.forbiddenForUnionMembers(u, unionName), - "forbidden-for-union-members" - ); + const { forbiddenNames, forbiddenNamespaces } = + this.processForbiddenWordsInfo( + this.forbiddenForUnionMembers(u, unionName), + "forbidden-for-union-members", + ); let ns: Namespace; if (this.unionMembersInGlobalNamespace) { ns = this.globalNamespace; } else { - ns = new Namespace(u.getCombinedName(), this.globalNamespace, forbiddenNamespaces, forbiddenNames); + ns = new Namespace( + u.getCombinedName(), + this.globalNamespace, + forbiddenNamespaces, + forbiddenNames, + ); } - let names = new Map(); + const names = new Map(); for (const t of u.members) { - const name = this.makeNameForUnionMember(u, unionName, followTargetType(t)); + const name = this.makeNameForUnionMember( + u, + unionName, + followTargetType(t), + ); names.set(t, ns.add(name)); } @@ -496,13 +682,19 @@ export abstract class ConvenienceRenderer extends Renderer { 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. const alternative = `${e.getCombinedName()}_${caseName}`; - const order = assignedName === undefined ? enumCaseNameOrder : assignedEnumCaseNameOrder; - const names = assignedName === undefined ? [caseName, alternative] : [assignedName]; + const order = + assignedName === undefined + ? enumCaseNameOrder + : assignedEnumCaseNameOrder; + const names = + assignedName === undefined + ? [caseName, alternative] + : [assignedName]; return new SimpleName(names, nonNull(this._enumCaseNamer), order); } @@ -510,27 +702,41 @@ export abstract class ConvenienceRenderer extends Renderer { 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" - ); + const { forbiddenNames, forbiddenNamespaces } = + this.processForbiddenWordsInfo( + this.forbiddenForEnumCases(e, enumName), + "forbidden-for-enum-cases", + ); let ns: Namespace; if (this.enumCasesInGlobalNamespace) { ns = this.globalNamespace; } else { - ns = new Namespace(e.getCombinedName(), this.globalNamespace, forbiddenNamespaces, forbiddenNames); + ns = new Namespace( + e.getCombinedName(), + this.globalNamespace, + forbiddenNamespaces, + forbiddenNames, + ); } - let names = new Map(); + const names = new Map(); const accessorNames = enumCaseNames(e, this.targetLanguage.name); for (const caseName of e.cases) { - const [assignedName, isFixed] = getAccessorName(accessorNames, caseName); + const [assignedName, isFixed] = getAccessorName( + accessorNames, + caseName, + ); let name: Name; if (isFixed) { name = new FixedName(defined(assignedName)); } else { - name = this.makeNameForEnumCase(e, enumName, caseName, assignedName); + name = this.makeNameForEnumCase( + e, + enumName, + caseName, + assignedName, + ); } names.set(caseName, ns.add(name)); @@ -547,7 +753,9 @@ export abstract class ConvenienceRenderer extends Renderer { if (propertyNameds.get(n) === undefined) return undefined; return p.type; }); - const sortedMap = mapSortBy(filteredMap, (_, n) => defined(names.get(defined(propertyNameds.get(n))))); + const sortedMap = mapSortBy(filteredMap, (_, n) => + defined(names.get(defined(propertyNameds.get(n)))), + ); return new Set(sortedMap.values()); } @@ -588,7 +796,9 @@ export abstract class ConvenienceRenderer extends Renderer { return this.enums.size > 0; } - protected proposedUnionMemberNameForTypeKind(_kind: TypeKind): string | null { + protected proposedUnionMemberNameForTypeKind( + _kind: TypeKind, + ): string | null { return null; } @@ -596,9 +806,11 @@ export abstract class ConvenienceRenderer extends Renderer { _u: UnionType, _unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { - const simpleName = this.proposedUnionMemberNameForTypeKind(fieldType.kind); + const simpleName = this.proposedUnionMemberNameForTypeKind( + fieldType.kind, + ); if (simpleName !== null) { return simpleName; } @@ -606,28 +818,29 @@ export abstract class ConvenienceRenderer extends Renderer { const typeNameForUnionMember = (t: Type): string => matchTypeExhaustive( t, - _noneType => { + (_noneType) => { return panic("none type should have been replaced"); }, - _anyType => "anything", - _nullType => "null", - _boolType => "bool", - _integerType => "integer", - _doubleType => "double", - _stringType => "string", - arrayType => typeNameForUnionMember(arrayType.items) + "_array", - classType => lookup(this.nameForNamedType(classType)), - mapType => typeNameForUnionMember(mapType.values) + "_map", - objectType => { + (_anyType) => "anything", + (_nullType) => "null", + (_boolType) => "bool", + (_integerType) => "integer", + (_doubleType) => "double", + (_stringType) => "string", + (arrayType) => + typeNameForUnionMember(arrayType.items) + "_array", + (classType) => lookup(this.nameForNamedType(classType)), + (mapType) => typeNameForUnionMember(mapType.values) + "_map", + (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("-", "_") + (_enumType) => "enum", + (_unionType) => "union", + (transformedType) => transformedType.kind.replace("-", "_"), ); return typeNameForUnionMember(fieldType); @@ -642,7 +855,9 @@ export abstract class ConvenienceRenderer extends Renderer { } protected isImplicitCycleBreaker(_t: Type): boolean { - return panic("A renderer that invokes isCycleBreakerType must implement isImplicitCycleBreaker"); + return panic( + "A renderer that invokes isCycleBreakerType must implement isImplicitCycleBreaker", + ); } protected canBreakCycles(_t: Type): boolean { @@ -653,8 +868,8 @@ export abstract class ConvenienceRenderer extends Renderer { if (this._cycleBreakerTypes === undefined) { this._cycleBreakerTypes = cycleBreakerTypesForGraph( this.typeGraph, - s => this.isImplicitCycleBreaker(s), - s => this.canBreakCycles(s) + (s) => this.isImplicitCycleBreaker(s), + (s) => this.canBreakCycles(s), ); } @@ -664,7 +879,7 @@ export abstract class ConvenienceRenderer extends Renderer { 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) { @@ -673,19 +888,22 @@ export abstract class ConvenienceRenderer extends Renderer { topLevels = this.topLevels; } - return this.forEachWithBlankLines(topLevels, blankLocations, (t, name, pos) => - f(t, this.nameStoreView.getForTopLevel(name), pos) + return this.forEachWithBlankLines( + topLevels, + blankLocations, + (t, name, pos) => + f(t, this.nameStoreView.getForTopLevel(name), pos), ); } protected forEachDeclaration( blankLocations: BlankLineConfig, - f: (decl: Declaration, position: ForEachPosition) => void + f: (decl: Declaration, position: ForEachPosition) => void, ): void { this.forEachWithBlankLines( iterableEnumerate(defined(this._declarationIR).declarations), blankLocations, - (decl, _, pos) => f(decl, pos) + (decl, _, pos) => f(decl, pos), ); } @@ -705,29 +923,44 @@ export abstract class ConvenienceRenderer extends Renderer { protected sortClassProperties( properties: ReadonlyMap, - propertyNames: ReadonlyMap + propertyNames: ReadonlyMap, ): ReadonlyMap { if (this._alphabetizeProperties) { - return mapSortBy(properties, (_p: ClassProperty, jsonName: string) => { - const name = defined(propertyNames.get(jsonName)); - return defined(this.names.get(name)); - }); - } else { - return properties; + return mapSortBy( + properties, + (_p: ClassProperty, jsonName: string) => { + const name = defined(propertyNames.get(jsonName)); + return defined(this.names.get(name)); + }, + ); } + + return properties; } 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); - this.forEachWithBlankLines(sortedProperties, blankLocations, (p, jsonName, pos) => { - const name = defined(propertyNames.get(jsonName)); - f(name, jsonName, p, pos); - }); + const sortedProperties = this.sortClassProperties( + o.getProperties(), + propertyNames, + ); + this.forEachWithBlankLines( + sortedProperties, + blankLocations, + (p, jsonName, pos) => { + const name = defined(propertyNames.get(jsonName)); + f(name, jsonName, p, pos); + }, + ); } protected nameForUnionMember(u: UnionType, t: Type): Name { @@ -744,14 +977,17 @@ export abstract class ConvenienceRenderer extends Renderer { 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 ?? u.members; if (sortOrder === null) { sortOrder = (n): string => defined(this.names.get(n)); } - const memberNames = mapFilter(defined(this._memberNamesStoreView).get(u), (_, t) => iterateMembers.has(t)); + const memberNames = mapFilter( + defined(this._memberNamesStoreView).get(u), + (_, t) => iterateMembers.has(t), + ); const sortedMemberNames = mapSortBy(memberNames, sortOrder); this.forEachWithBlankLines(sortedMemberNames, blankLocations, f); } @@ -759,56 +995,80 @@ export abstract class ConvenienceRenderer extends Renderer { 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))); + const sortedCaseNames = mapSortBy(caseNames, (n) => + defined(this.names.get(n)), + ); this.forEachWithBlankLines(sortedCaseNames, blankLocations, f); } 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); + this.forEachWithBlankLines( + defined(this._namesForTransformations), + blankLocations, + f, + ); } protected forEachSpecificNamedType( blankLocations: BlankLineConfig, types: Iterable<[T, 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)); + this.forEachWithBlankLines(types, blankLocations, (t, _, pos) => + f(t, this.nameForNamedType(t), pos), + ); } 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); + this.forEachSpecificNamedType( + blankLocations, + defined(this._namedObjects).entries(), + f, + ); } 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( 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); + this.forEachSpecificNamedType( + blankLocations, + this.namedUnions.entries(), + f, + ); } 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) { @@ -824,32 +1084,56 @@ export abstract class ConvenienceRenderer extends Renderer { protected forEachNamedType( blankLocations: BlankLineConfig, objectFunc: - | ((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 + | (( + 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, ): void { - this.forEachWithBlankLines(defined(this._namedTypes).entries(), blankLocations, (t, _, pos) => { - const name = this.nameForNamedType(t); - 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(t, name, pos); - } else if (t instanceof EnumType) { - enumFunc(t, name, pos); - } else if (t instanceof UnionType) { - unionFunc(t, name, pos); - } else { - return panic("Named type that's neither a class nor union"); - } - }); + this.forEachWithBlankLines( + defined(this._namedTypes).entries(), + blankLocations, + (t, _, pos) => { + const name = this.nameForNamedType(t); + 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(t, name, pos); + } else if (t instanceof EnumType) { + enumFunc(t, name, pos); + } else if (t instanceof UnionType) { + unionFunc(t, name, pos); + } else { + return panic("Named type that's neither a class nor union"); + } + }, + ); } // 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 { - return serializeRenderResult(sourcelikeToSource(src), this.names, "").lines.join("\n"); + return serializeRenderResult( + sourcelikeToSource(src), + this.names, + "", + ).lines.join("\n"); } protected get commentLineStart(): string { @@ -857,7 +1141,7 @@ export abstract class ConvenienceRenderer extends Renderer { } protected emitComments(comments: Comment[]): void { - comments.forEach(comment => { + comments.forEach((comment) => { if (isStringComment(comment)) { this.emitCommentLines([comment]); } else if ("lines" in comment) { @@ -879,8 +1163,8 @@ export abstract class ConvenienceRenderer extends Renderer { firstLineStart = lineStart, lineEnd, beforeComment, - afterComment - }: CommentOptions = {} + afterComment, + }: CommentOptions = {}, ): void { if (beforeComment !== undefined) { this.emitLine(beforeComment); @@ -919,7 +1203,11 @@ export abstract class ConvenienceRenderer extends Renderer { 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 = (): void => { @@ -943,23 +1231,32 @@ export abstract class ConvenienceRenderer extends Renderer { private processGraph(): void { this._declarationIR = declarationsForGraph( this.typeGraph, - this.needsTypeDeclarationBeforeUse ? (t): boolean => this.canBeForwardDeclared(t) : undefined, - t => this.childrenOfType(t), - t => { + this.needsTypeDeclarationBeforeUse + ? (t): boolean => this.canBeForwardDeclared(t) + : undefined, + (t) => this.childrenOfType(t), + (t) => { if (t instanceof UnionType) { return this.unionNeedsName(t); } return isNamedType(t); - } + }, ); const types = this.typeGraph.allTypesUnordered(); - this._haveUnions = iterableSome(types, t => t instanceof UnionType); - this._haveMaps = iterableSome(types, t => t instanceof MapType); - const classTypes = setFilter(types, t => t instanceof ClassType) as Set; - this._haveOptionalProperties = iterableSome(classTypes, c => mapSome(c.getProperties(), p => p.isOptional)); - this._namedTypes = this._declarationIR.declarations.filter(d => d.kind === "define").map(d => d.type); + this._haveUnions = iterableSome(types, (t) => t instanceof UnionType); + this._haveMaps = iterableSome(types, (t) => t instanceof MapType); + const classTypes = setFilter( + types, + (t) => t instanceof ClassType, + ) as Set; + this._haveOptionalProperties = iterableSome(classTypes, (c) => + mapSome(c.getProperties(), (p) => p.isOptional), + ); + this._namedTypes = this._declarationIR.declarations + .filter((d) => d.kind === "define") + .map((d) => d.type); const { objects, enums, unions } = separateNamedTypes(this._namedTypes); this._namedObjects = new Set(objects); this._namedEnums = new Set(enums); @@ -971,7 +1268,9 @@ export abstract class ConvenienceRenderer extends Renderer { this.emitSourceStructure(givenOutputFilename); } - protected forEachType(process: (t: Type) => TResult): Set { + protected forEachType( + process: (t: Type) => TResult, + ): Set { const visitedTypes = new Set(); const processed = new Set(); const queue = Array.from(this.typeGraph.topLevels.values()); diff --git a/packages/quicktype-core/src/CycleBreaker.ts b/packages/quicktype-core/src/CycleBreaker.ts index 9497d914..818b25c3 100644 --- a/packages/quicktype-core/src/CycleBreaker.ts +++ b/packages/quicktype-core/src/CycleBreaker.ts @@ -2,7 +2,7 @@ import { assert, panic } from "./support/Support"; export function breakCycles( outEdges: number[][], - chooseBreaker: (cycle: number[]) => [number, T] + chooseBreaker: (cycle: number[]) => [number, T], ): Array<[number, T]> { const numNodes = outEdges.length; const inEdges: number[][] = []; @@ -59,7 +59,10 @@ export function breakCycles( continue; } - assert(inDegree[i] === 0 || outDegree[i] === 0, "Can't have nodes in the worklist with in and out edges"); + assert( + inDegree[i] === 0 || outDegree[i] === 0, + "Can't have nodes in the worklist with in and out edges", + ); removeNode(i); continue; @@ -83,7 +86,7 @@ export function breakCycles( // We could count the number of reachable nodes for all nodes in the graph, // and then pick one of the nodes with the lowest number, which would pick // the dependee cycle. - const maybeEdge = outEdges[n].find(x => !done[x]); + const maybeEdge = outEdges[n].find((x) => !done[x]); if (maybeEdge === undefined) { return panic("Presumed cycle is not a cycle"); } diff --git a/packages/quicktype-core/src/DateTime.ts b/packages/quicktype-core/src/DateTime.ts index 9f2bc4ae..7c2f4b04 100644 --- a/packages/quicktype-core/src/DateTime.ts +++ b/packages/quicktype-core/src/DateTime.ts @@ -61,6 +61,10 @@ export class DefaultDateTimeRecognizer implements DateTimeRecognizer { 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]); + 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 30b763ee..8ee30c34 100644 --- a/packages/quicktype-core/src/DeclarationIR.ts +++ b/packages/quicktype-core/src/DeclarationIR.ts @@ -1,10 +1,16 @@ -import { iterableFirst, setFilter, setIntersect, setSubtract, setUnionInto } from "collection-utils"; +import { + iterableFirst, + setFilter, + setIntersect, + setSubtract, + setUnionInto, +} from "collection-utils"; import { Graph } from "./Graph"; import { messageError } from "./Messages"; import { assert, defined, panic } from "./support/Support"; -import { type Type } from "./Type/Type"; -import { type TypeGraph } from "./Type/TypeGraph"; +import type { Type } from "./Type/Type"; +import type { TypeGraph } from "./Type/TypeGraph"; export type DeclarationKind = "forward" | "define"; @@ -18,13 +24,17 @@ export class DeclarationIR { public constructor( declarations: Iterable, - public readonly forwardedTypes: Set + 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) { @@ -43,7 +53,7 @@ function findBreaker(t: Type, path: readonly Type[], canBreak: ((t: Type) => boo 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(); @@ -88,7 +98,7 @@ 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 { @@ -122,7 +132,10 @@ export function declarationsForGraph( // 1. Only one node in the cycle needs a declaration, in which // case it's the breaker, and no forward declaration is necessary. if (declarationNeeded.size === 1) { - declarations.push({ kind: "define", type: defined(iterableFirst(declarationNeeded)) }); + declarations.push({ + kind: "define", + type: defined(iterableFirst(declarationNeeded)), + }); return; } @@ -137,7 +150,10 @@ export function declarationsForGraph( // declaration, so we can pick any one. This is not a forward // declaration, either. if (declarationNeeded.size === 0) { - declarations.push({ kind: "define", type: defined(iterableFirst(component)) }); + declarations.push({ + kind: "define", + type: defined(iterableFirst(component)), + }); return; } @@ -158,9 +174,12 @@ export function declarationsForGraph( // there are none, we're stuck. If there are, we take them out of // the component and try the whole thing again recursively. Then // we declare the types we previously forward-declared. - const forwardDeclarable = setFilter(component, canBeForwardDeclared); + const forwardDeclarable = setFilter( + component, + canBeForwardDeclared, + ); if (forwardDeclarable.size === 0) { - return messageError("IRNoForwardDeclarableTypeInCycle", {}); + messageError("IRNoForwardDeclarableTypeInCycle", {}); } for (const t of forwardDeclarable) { @@ -169,7 +188,9 @@ export function declarationsForGraph( setUnionInto(forwardedTypes, forwardDeclarable); const rest = setSubtract(component, forwardDeclarable); - const restGraph = new Graph(rest, true, t => setIntersect(childrenOfType(t), rest)); + const restGraph = new Graph(rest, true, (t) => + setIntersect(childrenOfType(t), rest), + ); processGraph(restGraph, false); for (const t of forwardDeclarable) { declarations.push({ kind: "define", type: t }); diff --git a/packages/quicktype-core/src/GatherNames.ts b/packages/quicktype-core/src/GatherNames.ts index bf325c69..c99da4bf 100644 --- a/packages/quicktype-core/src/GatherNames.ts +++ b/packages/quicktype-core/src/GatherNames.ts @@ -1,11 +1,16 @@ import { setMap, setSortBy, setUnion } from "collection-utils"; import * as pluralize from "pluralize"; -import { TooManyTypeNames, TypeNames, namesTypeAttributeKind, tooManyNamesThreshold } from "./attributes/TypeNames"; +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/Type"; -import { type TypeGraph } from "./Type/TypeGraph"; +import type { TypeGraph } from "./Type/TypeGraph"; import { matchCompoundType, nullableFromUnion } from "./Type/TypeUtils"; class UniqueQueue { @@ -85,7 +90,11 @@ 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 { +export function gatherNames( + graph: TypeGraph, + destructive: boolean, + debugPrint: boolean, +): void { function setNames(t: Type, tn: TypeNames): void { graph.attributeStore.set(namesTypeAttributeKind, t, tn); } @@ -161,23 +170,34 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: const values = t.getAdditionalProperties(); if (values !== undefined) { - addNames(values, names === null ? null : setMap(names, pluralize.singular)); + addNames( + values, + names === null ? null : setMap(names, pluralize.singular), + ); } } else { matchCompoundType( t, - arrayType => { - addNames(arrayType.items, names === null ? null : setMap(names, pluralize.singular)); + (arrayType) => { + addNames( + arrayType.items, + names === null + ? null + : setMap(names, pluralize.singular), + ); }, - _classType => panic("We handled this above"), - _mapType => panic("We handled this above"), - _objectType => panic("We handled this above"), - unionType => { - const members = setSortBy(unionType.members, member => member.kind); + (_classType) => panic("We handled this above"), + (_mapType) => panic("We handled this above"), + (_objectType) => panic("We handled this above"), + (unionType) => { + const members = setSortBy( + unionType.members, + (member) => member.kind, + ); for (const memberType of members) { addNames(memberType, names); } - } + }, ); } } @@ -188,18 +208,26 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: if (names === undefined) return; const index = t.index; - console.log(`${index}: ${names === null ? "*** too many ***" : Array.from(names).join(" ")}`); + console.log( + `${index}: ${names === null ? "*** too many ***" : Array.from(names).join(" ")}`, + ); } } // null means there are too many - const directAlternativesForType = new Map | null>(); - const ancestorAlternativesForType = new Map | null>(); + const directAlternativesForType = new Map< + Type, + ReadonlySet | null + >(); + const ancestorAlternativesForType = new Map< + Type, + ReadonlySet | null + >(); const pairsProcessed = new Map>(); function addAlternatives( existing: ReadonlySet | undefined, - alternatives: string[] + alternatives: string[], ): ReadonlySet | undefined | null { if (alternatives.length === 0) { return existing; @@ -217,7 +245,11 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: return null; } - function processType(ancestor: Type | undefined, t: Type, alternativeSuffix: string | undefined): void { + function processType( + ancestor: Type | undefined, + t: Type, + alternativeSuffix: string | undefined, + ): void { const names = defined(namesForType.get(t)); let processedEntry = pairsProcessed.get(ancestor); @@ -244,25 +276,42 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: } else if (ancestorNames !== undefined) { const alternatives: string[] = []; for (const name of names) { - alternatives.push(...Array.from(ancestorNames).map(an => `${an}_${name}`)); + alternatives.push( + ...Array.from(ancestorNames).map( + (an) => `${an}_${name}`, + ), + ); // FIXME: add alternatives with the suffix here, too? - alternatives.push(...Array.from(ancestorNames).map(an => `${an}_${name}_${t.kind}`)); + alternatives.push( + ...Array.from(ancestorNames).map( + (an) => `${an}_${name}_${t.kind}`, + ), + ); // FIXME: add alternatives with the suffix here, too? } - ancestorAlternatives = addAlternatives(ancestorAlternatives, alternatives); + ancestorAlternatives = addAlternatives( + ancestorAlternatives, + alternatives, + ); } } - if (alternativeSuffix !== undefined && directAlternatives !== null) { + if ( + alternativeSuffix !== undefined && + directAlternatives !== null + ) { const alternatives: string[] = []; for (const name of names) { // FIXME: we should only add these for names we couldn't singularize alternatives.push(`${name}_${alternativeSuffix}`); } - directAlternatives = addAlternatives(directAlternatives, alternatives); + directAlternatives = addAlternatives( + directAlternatives, + alternatives, + ); } } @@ -282,26 +331,38 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: const values = t.getAdditionalProperties(); if (values !== undefined) { - processType(properties.size === 0 ? ancestor : t, values, "value"); + processType( + properties.size === 0 ? ancestor : t, + values, + "value", + ); } } else { matchCompoundType( t, - arrayType => { + (arrayType) => { processType(ancestor, arrayType.items, "element"); }, - _classType => panic("We handled this above"), - _mapType => panic("We handled this above"), - _objectType => panic("We handled this above"), - unionType => { - const members = setSortBy(unionType.members, member => member.kind); - const unionHasGivenName = unionType.hasNames && !unionType.getNames().areInferred; - const unionIsAncestor = unionHasGivenName || nullableFromUnion(unionType) === null; - const ancestorForMembers = unionIsAncestor ? unionType : ancestor; + (_classType) => panic("We handled this above"), + (_mapType) => panic("We handled this above"), + (_objectType) => panic("We handled this above"), + (unionType) => { + const members = setSortBy( + unionType.members, + (member) => member.kind, + ); + const unionHasGivenName = + unionType.hasNames && !unionType.getNames().areInferred; + const unionIsAncestor = + unionHasGivenName || + nullableFromUnion(unionType) === null; + const ancestorForMembers = unionIsAncestor + ? unionType + : ancestor; for (const memberType of members) { processType(ancestorForMembers, memberType, undefined); } - } + }, ); } } @@ -326,7 +387,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); } @@ -346,18 +407,28 @@ export function gatherNames(graph: TypeGraph, destructive: boolean, debugPrint: if (ancestorAlternatives === null && directAlternatives === null) { alternatives = undefined; } else { - if (directAlternatives !== null && directAlternatives !== undefined) { + if ( + directAlternatives !== null && + directAlternatives !== undefined + ) { alternatives = directAlternatives; } else { alternatives = new Set(); } - if (ancestorAlternatives !== null && ancestorAlternatives !== undefined) { + if ( + ancestorAlternatives !== null && + ancestorAlternatives !== undefined + ) { alternatives = setUnion(alternatives, ancestorAlternatives); } } - typeNames = TypeNames.makeWithDistance(names, alternatives, destructive ? 1 : 10); + typeNames = TypeNames.makeWithDistance( + names, + alternatives, + destructive ? 1 : 10, + ); } setNames(t, t.hasNames ? t.getNames().add([typeNames]) : typeNames); diff --git a/packages/quicktype-core/src/Graph.ts b/packages/quicktype-core/src/Graph.ts index df186ce9..16690398 100644 --- a/packages/quicktype-core/src/Graph.ts +++ b/packages/quicktype-core/src/Graph.ts @@ -75,21 +75,33 @@ function stronglyConnectedComponents(successors: number[][]): number[][] { } } - assert(countComponentGraphNodes(sccs) === numNodes, "We didn't put all the nodes into SCCs"); + assert( + countComponentGraphNodes(sccs) === numNodes, + "We didn't put all the nodes into SCCs", + ); return sccs; } -function buildComponentOfNodeMap(successors: number[][], components: number[][]): number[] { +function buildComponentOfNodeMap( + successors: number[][], + components: number[][], +): number[] { const numComponents = components.length; const numNodes = successors.length; - assert(numNodes === countComponentGraphNodes(components), "Components don't match up with graph"); + assert( + numNodes === countComponentGraphNodes(components), + "Components don't match up with graph", + ); const componentOfNode: number[] = repeated(numNodes, -1); for (let c = 0; c < numComponents; c++) { for (const n of components[c]) { - assert(componentOfNode[n] < 0, "We have a node that's in two components"); + assert( + componentOfNode[n] < 0, + "We have a node that's in two components", + ); componentOfNode[n] = c; } } @@ -97,7 +109,10 @@ 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); @@ -177,15 +192,21 @@ export class Graph { public constructor( nodes: Iterable, invertDirection: boolean, - edges: number[][] | ((node: T) => ReadonlySet) + edges: number[][] | ((node: T) => ReadonlySet), ) { this._nodes = Array.from(nodes); - this._indexByNode = new Map(this._nodes.map((n, i): [T, number] => [n, i])); + this._indexByNode = new Map( + this._nodes.map((n, i): [T, number] => [n, i]), + ); let edgesArray: number[][]; if (Array.isArray(edges)) { edgesArray = edges; } else { - edgesArray = this._nodes.map(n => Array.from(edges(n)).map(s => defined(this._indexByNode.get(s)))); + edgesArray = this._nodes.map((n) => + Array.from(edges(n)).map((s) => + defined(this._indexByNode.get(s)), + ), + ); } if (invertDirection) { @@ -205,11 +226,15 @@ export class Graph { public findRoots(): ReadonlySet { const roots = findRoots(this._successors); - return new Set(roots.map(n => this._nodes[n])); + return new Set(roots.map((n) => this._nodes[n])); } // The subgraph starting at `root` must be acyclic. - public 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 => { @@ -234,15 +259,21 @@ export class Graph { public stronglyConnectedComponents(): Graph> { const components = stronglyConnectedComponents(this._successors); - const componentSuccessors = buildMetaSuccessors(this._successors, components); + const componentSuccessors = buildMetaSuccessors( + this._successors, + components, + ); return new Graph( - components.map(ns => setMap(ns, n => this._nodes[n])), + components.map((ns) => setMap(ns, (n) => this._nodes[n])), false, - componentSuccessors + componentSuccessors, ); } - public 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 060afe34..71cb44a8 100644 --- a/packages/quicktype-core/src/GraphRewriting.ts +++ b/packages/quicktype-core/src/GraphRewriting.ts @@ -1,24 +1,40 @@ import { EqualityMap, mapMap } from "collection-utils"; -import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; +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"; +import type { + ClassProperty, + MaybeTypeIdentity, + PrimitiveTypeKind, + Type, +} from "./Type"; import { TypeBuilder } from "./Type/TypeBuilder"; -import { type StringTypeMapping } from "./Type/TypeBuilderUtils"; -import { type TypeGraph } from "./Type/TypeGraph"; +import type { StringTypeMapping } from "./Type/TypeBuilderUtils"; +import type { TypeGraph } from "./Type/TypeGraph"; import { type TypeRef, assertTypeRefGraph, derefTypeRef, isTypeRef, typeAndAttributesForTypeRef, - typeRefIndex + typeRefIndex, } from "./Type/TypeRef"; import { combineTypeAttributesOfTypes } from "./Type/TypeUtils"; 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 { @@ -31,7 +47,7 @@ export class TypeReconstituter { 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 { @@ -41,7 +57,10 @@ export class TypeReconstituter { } private builderForSetting(): TBuilder { - assert(this._wasUsed && this._typeRef !== undefined, "Can't set type members before constructing a type"); + assert( + this._wasUsed && this._typeRef !== undefined, + "Can't set type members before constructing a type", + ); return this._typeBuilder; } @@ -67,21 +86,36 @@ export class TypeReconstituter { 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"); + 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); - } 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 readonly TypeRef[]; } + + const maybeRefs = Array.from(trefs).map((tref) => + this._typeBuilder.lookupTypeRefs([tref], undefined, false), + ); + if (maybeRefs.some((tref) => tref === undefined)) { + return undefined; + } + + return maybeRefs as readonly TypeRef[]; } - public 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"); + assert( + resultValues.length === trefs.size, + "Didn't get back the correct number of types", + ); const result = new Map(); let i = 0; for (const k of trefs.keys()) { @@ -94,76 +128,118 @@ export class TypeReconstituter { 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"); + 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); - } else { - return Array.from(trefs).map(tref => this._typeBuilder.reconstituteTypeRef(tref)); } + + return Array.from(trefs).map((tref) => + this._typeBuilder.reconstituteTypeRef(tref), + ); } - public reconstituteMap(trefs: ReadonlyMap): ReadonlyMap { - return mapMap(trefs, tref => this._typeBuilder.reconstituteTypeRef(tref)); + public reconstituteMap( + trefs: ReadonlyMap, + ): ReadonlyMap { + return mapMap(trefs, (tref) => + this._typeBuilder.reconstituteTypeRef(tref), + ); } public getPrimitiveType(kind: PrimitiveTypeKind): void { - this.register(this.builderForNewType().getPrimitiveType(kind, this._typeAttributes, this._forwardingRef)); + this.register( + this.builderForNewType().getPrimitiveType( + kind, + this._typeAttributes, + this._forwardingRef, + ), + ); } public getEnumType(cases: ReadonlySet): void { - this.register(this.builderForNewType().getEnumType(this._typeAttributes, cases, this._forwardingRef)); + this.register( + this.builderForNewType().getEnumType( + this._typeAttributes, + cases, + this._forwardingRef, + ), + ); } public getUniqueMapType(): void { - this.registerAndAddAttributes(this.builderForNewType().getUniqueMapType(this._forwardingRef)); + this.registerAndAddAttributes( + this.builderForNewType().getUniqueMapType(this._forwardingRef), + ); } public getMapType(values: TypeRef): void { - this.register(this.builderForNewType().getMapType(this._typeAttributes, values, this._forwardingRef)); + this.register( + this.builderForNewType().getMapType( + this._typeAttributes, + values, + this._forwardingRef, + ), + ); } public getUniqueArrayType(): void { - this.registerAndAddAttributes(this.builderForNewType().getUniqueArrayType(this._forwardingRef)); + this.registerAndAddAttributes( + this.builderForNewType().getUniqueArrayType(this._forwardingRef), + ); } public getArrayType(items: TypeRef): void { - this.register(this.builderForNewType().getArrayType(this._typeAttributes, items, this._forwardingRef)); + this.register( + this.builderForNewType().getArrayType( + this._typeAttributes, + items, + this._forwardingRef, + ), + ); } public setArrayItems(items: TypeRef): void { this.builderForSetting().setArrayItems(this.getResult(), items); } - public makeClassProperty(tref: TypeRef, isOptional: boolean): ClassProperty { + public makeClassProperty( + tref: TypeRef, + isOptional: boolean, + ): ClassProperty { return this._typeBuilder.makeClassProperty(tref, isOptional); } public getObjectType( properties: ReadonlyMap, - additionalProperties: TypeRef | undefined + additionalProperties: TypeRef | undefined, ): void { this.register( this.builderForNewType().getUniqueObjectType( this._typeAttributes, properties, additionalProperties, - this._forwardingRef - ) + this._forwardingRef, + ), ); } 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, + ), ); } @@ -173,48 +249,92 @@ export class TypeReconstituter { return; } - this.register(this.builderForNewType().getClassType(this._typeAttributes, properties, this._forwardingRef)); + this.register( + this.builderForNewType().getClassType( + this._typeAttributes, + properties, + this._forwardingRef, + ), + ); } - public 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, + ), ); } public setObjectProperties( properties: ReadonlyMap, - additionalProperties: TypeRef | undefined + additionalProperties: TypeRef | undefined, ): void { - this.builderForSetting().setObjectProperties(this.getResult(), properties, additionalProperties); + this.builderForSetting().setObjectProperties( + this.getResult(), + properties, + additionalProperties, + ); } public getUnionType(members: ReadonlySet): void { - this.register(this.builderForNewType().getUnionType(this._typeAttributes, members, this._forwardingRef)); + this.register( + this.builderForNewType().getUnionType( + this._typeAttributes, + members, + this._forwardingRef, + ), + ); } public getUniqueUnionType(): void { this.register( - this.builderForNewType().getUniqueUnionType(this._typeAttributes, undefined, this._forwardingRef) + this.builderForNewType().getUniqueUnionType( + this._typeAttributes, + undefined, + this._forwardingRef, + ), ); } public getIntersectionType(members: ReadonlySet): void { - this.register(this.builderForNewType().getIntersectionType(this._typeAttributes, members, this._forwardingRef)); + this.register( + this.builderForNewType().getIntersectionType( + this._typeAttributes, + members, + this._forwardingRef, + ), + ); } public getUniqueIntersectionType(members?: ReadonlySet): void { this.register( - this.builderForNewType().getUniqueIntersectionType(this._typeAttributes, members, this._forwardingRef) + this.builderForNewType().getUniqueIntersectionType( + this._typeAttributes, + members, + this._forwardingRef, + ), ); } public setSetOperationMembers(members: ReadonlySet): void { - this.builderForSetting().setSetOperationMembers(this.getResult(), members); + this.builderForSetting().setSetOperationMembers( + this.getResult(), + members, + ); } } -export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements TypeLookerUp { +export abstract class BaseGraphRewriteBuilder + extends TypeBuilder + implements TypeLookerUp +{ protected readonly reconstitutedTypes: Map = new Map(); private _lostTypeAttributes = false; @@ -226,20 +346,20 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ stringTypeMapping: StringTypeMapping, alphabetizeProperties: boolean, graphHasProvenanceAttributes: boolean, - protected readonly debugPrint: boolean + protected readonly debugPrint: boolean, ) { super( stringTypeMapping, alphabetizeProperties, false, false, - graphHasProvenanceAttributes + graphHasProvenanceAttributes, ); } public withForwardingRef( maybeForwardingRef: TypeRef | undefined, - typeCreator: (forwardingRef: TypeRef) => TypeRef + typeCreator: (forwardingRef: TypeRef) => TypeRef, ): TypeRef { if (maybeForwardingRef !== undefined) { return typeCreator(maybeForwardingRef); @@ -247,29 +367,36 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ const forwardingRef = this.reserveTypeRef(); const actualRef = typeCreator(forwardingRef); - assert(actualRef === forwardingRef, "Type creator didn't return its forwarding ref"); + assert( + actualRef === forwardingRef, + "Type creator didn't return its forwarding ref", + ); return actualRef; } - public reconstituteType(t: Type, attributes?: TypeAttributes, forwardingRef?: TypeRef): TypeRef { + public reconstituteType( + t: Type, + attributes?: TypeAttributes, + forwardingRef?: TypeRef, + ): TypeRef { return this.reconstituteTypeRef(t.typeRef, attributes, forwardingRef); } public abstract lookupTypeRefs( typeRefs: TypeRef[], forwardingRef?: TypeRef, - replaceSet?: boolean + replaceSet?: boolean, ): TypeRef | undefined; protected abstract forceReconstituteTypeRef( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef; public reconstituteTypeRef( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef { const maybeRef = this.lookupTypeRefs([originalRef], maybeForwardingRef); if (maybeRef !== undefined) { @@ -280,15 +407,27 @@ export abstract class BaseGraphRewriteBuilder extends TypeBuilder implements Typ return maybeRef; } - return this.forceReconstituteTypeRef(originalRef, attributes, maybeForwardingRef); + return this.forceReconstituteTypeRef( + originalRef, + attributes, + maybeForwardingRef, + ); } - public 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 { - assert(typeRefs.length > 0, "Must have at least one type to reconstitute"); + 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); } @@ -332,14 +471,14 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { 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) { @@ -360,24 +499,42 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { 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"); + 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 { - return panic("We can't add forwarding intersections when we're removing forwarding intersections"); + protected addForwardingIntersection( + _forwardingRef: TypeRef, + _tref: TypeRef, + ): TypeRef { + return panic( + "We can't add forwarding intersections when we're removing forwarding intersections", + ); } - public lookupTypeRefs(typeRefs: TypeRef[], forwardingRef?: TypeRef): TypeRef | undefined { - assert(forwardingRef === undefined, "We can't have a forwarding ref when we remap"); + 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); - const first = this.reconstitutedTypes.get(typeRefIndex(this.getMapTarget(typeRefs[0]))); + const first = this.reconstitutedTypes.get( + typeRefIndex(this.getMapTarget(typeRefs[0])), + ); if (first === undefined) return undefined; for (let i = 1; i < typeRefs.length; i++) { - const other = this.reconstitutedTypes.get(typeRefIndex(this.getMapTarget(typeRefs[i]))); + const other = this.reconstitutedTypes.get( + typeRefIndex(this.getMapTarget(typeRefs[i])), + ); if (first !== other) return undefined; } @@ -387,24 +544,33 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { protected forceReconstituteTypeRef( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef { originalRef = this.getMapTarget(originalRef); const index = typeRefIndex(originalRef); - assert(this.reconstitutedTypes.get(index) === undefined, "Type has already been reconstituted"); + assert( + this.reconstitutedTypes.get(index) === undefined, + "Type has already been reconstituted", + ); - assert(maybeForwardingRef === undefined, "We can't have a forwarding ref when we remap"); + assert( + maybeForwardingRef === undefined, + "We can't have a forwarding ref when we remap", + ); - return this.withForwardingRef(undefined, forwardingRef => { + return this.withForwardingRef(undefined, (forwardingRef) => { this.reconstitutedTypes.set(index, forwardingRef); if (this.debugPrint) { - console.log(`${this.debugPrintIndentation}reconstituting ${index} as ${typeRefIndex(forwardingRef)}`); + console.log( + `${this.debugPrintIndentation}reconstituting ${index} as ${typeRefIndex(forwardingRef)}`, + ); this.changeDebugPrintIndent(1); } - const [originalType, originalAttributes] = typeAndAttributesForTypeRef(originalRef, this.originalGraph); + const [originalType, originalAttributes] = + typeAndAttributesForTypeRef(originalRef, this.originalGraph); const attributeSources = this._attributeSources.get(originalType); if (attributes === undefined) { @@ -415,13 +581,15 @@ 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), + ), ); } @@ -432,13 +600,18 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { this.canonicalOrder, newAttributes, forwardingRef, - tref => { - assert(tref === forwardingRef, "Reconstituted type as a different ref"); + (tref) => { + assert( + tref === forwardingRef, + "Reconstituted type as a different ref", + ); if (this.debugPrint) { this.changeDebugPrintIndent(-1); - console.log(`${this.debugPrintIndentation}reconstituted ${index} as ${typeRefIndex(tref)}`); + console.log( + `${this.debugPrintIndentation}reconstituted ${index} as ${typeRefIndex(tref)}`, + ); } - } + }, ); originalType.reconstitute(reconstituter, this.canonicalOrder); return reconstituter.getResult(); @@ -446,10 +619,13 @@ export class GraphRemapBuilder extends BaseGraphRewriteBuilder { } } -export class GraphRewriteBuilder extends BaseGraphRewriteBuilder { +export class GraphRewriteBuilder< + T extends Type, +> extends BaseGraphRewriteBuilder { private readonly _setsToReplaceByMember: Map>; - private readonly _reconstitutedUnions: EqualityMap, TypeRef> = new EqualityMap(); + private readonly _reconstitutedUnions: EqualityMap, TypeRef> = + new EqualityMap(); public constructor( originalGraph: TypeGraph, @@ -461,15 +637,15 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder private readonly _replacer: ( typesToReplace: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef - ) => TypeRef + forwardingRef: TypeRef, + ) => TypeRef, ) { super( originalGraph, stringTypeMapping, alphabetizeProperties, graphHasProvenanceAttributes, - debugPrintReconstitution + debugPrintReconstitution, ); this._setsToReplaceByMember = new Map(); @@ -477,7 +653,10 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder const set = new Set(types); for (const t of set) { const index = t.index; - assert(!this._setsToReplaceByMember.has(index), "A type is member of more than one set to be replaced"); + assert( + !this._setsToReplaceByMember.has(index), + "A type is member of more than one set to be replaced", + ); this._setsToReplaceByMember.set(index, set); } } @@ -485,17 +664,25 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder public registerUnion(typeRefs: TypeRef[], reconstituted: TypeRef): void { const set = new Set(typeRefs); - assert(!this._reconstitutedUnions.has(set), "Cannot register reconstituted set twice"); + assert( + !this._reconstitutedUnions.has(set), + "Cannot register reconstituted set twice", + ); this._reconstitutedUnions.set(set, reconstituted); } - private replaceSet(typesToReplace: ReadonlySet, maybeForwardingRef: TypeRef | undefined): TypeRef { - return this.withForwardingRef(maybeForwardingRef, forwardingRef => { + 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)}` + `${this.debugPrintIndentation}replacing set ${Array.from( + typesToReplace, + ) + .map((t) => t.index.toString()) + .join(",")} as ${typeRefIndex(forwardingRef)}`, ); this.changeDebugPrintIndent(1); } @@ -508,14 +695,19 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder } const result = this._replacer(typesToReplace, this, forwardingRef); - assert(result === forwardingRef, "The forwarding ref got lost when replacing"); + assert( + result === forwardingRef, + "The forwarding ref got lost when replacing", + ); if (this.debugPrint) { this.changeDebugPrintIndent(-1); console.log( - `${this.debugPrintIndentation}replaced set ${Array.from(typesToReplace) - .map(t => t.index.toString()) - .join(",")} as ${typeRefIndex(forwardingRef)}` + `${this.debugPrintIndentation}replaced set ${Array.from( + typesToReplace, + ) + .map((t) => t.index.toString()) + .join(",")} as ${typeRefIndex(forwardingRef)}`, ); } @@ -526,9 +718,12 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder protected forceReconstituteTypeRef( originalRef: TypeRef, attributes?: TypeAttributes, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef { - const [originalType, originalAttributes] = typeAndAttributesForTypeRef(originalRef, this.originalGraph); + const [originalType, originalAttributes] = typeAndAttributesForTypeRef( + originalRef, + this.originalGraph, + ); const index = typeRefIndex(originalRef); if (this.debugPrint) { @@ -542,27 +737,42 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder attributes = combineTypeAttributes( "union", attributes, - this.reconstituteTypeAttributes(originalAttributes) + this.reconstituteTypeAttributes(originalAttributes), ); } - const reconstituter = new TypeReconstituter(this, this.canonicalOrder, attributes, maybeForwardingRef, tref => { - if (this.debugPrint) { - this.changeDebugPrintIndent(-1); - console.log(`${this.debugPrintIndentation}reconstituted ${index} as ${typeRefIndex(tref)}`); - } + const reconstituter = new TypeReconstituter( + this, + this.canonicalOrder, + attributes, + maybeForwardingRef, + (tref) => { + if (this.debugPrint) { + this.changeDebugPrintIndent(-1); + console.log( + `${this.debugPrintIndentation}reconstituted ${index} as ${typeRefIndex(tref)}`, + ); + } - if (maybeForwardingRef !== undefined) { - assert(tref === maybeForwardingRef, "We didn't pass the forwarding ref"); - } + if (maybeForwardingRef !== undefined) { + assert( + tref === maybeForwardingRef, + "We didn't pass the forwarding ref", + ); + } - const alreadyReconstitutedType = this.reconstitutedTypes.get(index); - if (alreadyReconstitutedType === undefined) { - this.reconstitutedTypes.set(index, tref); - } else { - assert(tref === alreadyReconstitutedType, "We reconstituted a type twice differently"); - } - }); + const alreadyReconstitutedType = + this.reconstitutedTypes.get(index); + if (alreadyReconstitutedType === undefined) { + this.reconstitutedTypes.set(index, tref); + } else { + assert( + tref === alreadyReconstitutedType, + "We reconstituted a type twice differently", + ); + } + }, + ); originalType.reconstitute(reconstituter, this.canonicalOrder); return reconstituter.getResult(); } @@ -583,7 +793,11 @@ 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. - public 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 @@ -592,7 +806,10 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder if (maybeRef !== undefined && maybeRef !== forwardingRef) { let allEqual = true; for (let i = 1; i < typeRefs.length; i++) { - if (this.reconstitutedTypes.get(typeRefIndex(typeRefs[i])) !== maybeRef) { + if ( + this.reconstitutedTypes.get(typeRefIndex(typeRefs[i])) !== + maybeRef + ) { allEqual = false; break; } @@ -610,13 +827,18 @@ export class GraphRewriteBuilder extends BaseGraphRewriteBuilder } // Is this set requested to be replaced? If not, we're out of options. - const maybeSet = this._setsToReplaceByMember.get(typeRefIndex(typeRefs[0])); + const maybeSet = this._setsToReplaceByMember.get( + typeRefIndex(typeRefs[0]), + ); if (maybeSet === undefined) { return undefined; } for (let i = 1; i < typeRefs.length; i++) { - if (this._setsToReplaceByMember.get(typeRefIndex(typeRefs[i])) !== maybeSet) { + if ( + this._setsToReplaceByMember.get(typeRefIndex(typeRefs[i])) !== + maybeSet + ) { return undefined; } } diff --git a/packages/quicktype-core/src/Inference.ts b/packages/quicktype-core/src/Inference.ts new file mode 100644 index 00000000..94bf2e82 --- /dev/null +++ b/packages/quicktype-core/src/Inference.ts @@ -0,0 +1,97 @@ +import type { TransformedStringTypeKind } from "./Type"; + +export interface InferenceFlag { + description: string; + explanation: string; + negationDescription: string; + order: number; + stringType?: TransformedStringTypeKind; +} + +export const inferenceFlagsObject = { + /** Whether to infer map types from JSON data */ + inferMaps: { + description: "Detect maps", + negationDescription: "Don't infer maps, always use classes", + explanation: "Infer maps when object keys look like map keys.", + 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, + }, + /** Whether to convert UUID strings to UUID objects */ + inferUuids: { + description: "Detect UUIDs", + 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, + }, + /** Whether to assume that JSON strings that look like dates are dates */ + inferDateTimes: { + description: "Detect dates & times", + negationDescription: "Don't infer dates or times", + explanation: "Infer dates from strings (partial support).", + stringType: "date-time" as TransformedStringTypeKind, + 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.', + stringType: "integer-string" as TransformedStringTypeKind, + 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.', + stringType: "bool-string" as TransformedStringTypeKind, + order: 6, + }, + /** Combine similar classes. This doesn't apply to classes from a schema, only from inference. */ + combineClasses: { + description: "Merge similar classes", + negationDescription: "Don't combine similar classes", + explanation: + "Combine classes with significantly overlapping properties,\ntreating contingent properties as nullable.", + order: 7, + }, + /** Whether to treat $ref as references within JSON */ + ignoreJsonRefs: { + description: "Don't treat $ref as a reference in JSON", + 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, + }, +}; +export type InferenceFlagName = keyof typeof inferenceFlagsObject; +export const inferenceFlagNames = Object.getOwnPropertyNames( + inferenceFlagsObject, +) as InferenceFlagName[]; +export const inferenceFlags: { [F in InferenceFlagName]: InferenceFlag } = + inferenceFlagsObject; + +export type InferenceFlags = { [F in InferenceFlagName]: boolean }; + +function makeDefaultInferenceFlags(): InferenceFlags { + const flags = {} as InferenceFlags; + for (const flag of inferenceFlagNames) { + flags[flag] = true; + } + + return flags; +} + +export const defaultInferenceFlags = makeDefaultInferenceFlags(); diff --git a/packages/quicktype-core/src/MakeTransformations.ts b/packages/quicktype-core/src/MakeTransformations.ts index bc42e628..9707357a 100644 --- a/packages/quicktype-core/src/MakeTransformations.ts +++ b/packages/quicktype-core/src/MakeTransformations.ts @@ -1,12 +1,26 @@ -import { arraySortByInto, iterableFirst, iterableSome, mapMapEntries, setFilter, withDefault } from "collection-utils"; +import { + arraySortByInto, + iterableFirst, + iterableSome, + mapMapEntries, + setFilter, + withDefault, +} from "collection-utils"; -import { minMaxLengthForType, minMaxValueForType } from "./attributes/Constraints"; +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 { + 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 { TargetLanguage } from "./TargetLanguage"; import { ArrayDecodingTransformer, ChoiceTransformer, @@ -20,7 +34,7 @@ import { Transformation, type Transformer, UnionInstantiationTransformer, - transformationTypeAttributeKind + transformationTypeAttributeKind, } from "./Transformers"; import { ArrayType, @@ -32,20 +46,26 @@ import { UnionType, isNumberTypeKind, isPrimitiveStringTypeKind, - targetTypeKindForTransformedStringTypeKind + targetTypeKindForTransformedStringTypeKind, } from "./Type"; -import { type TypeGraph } from "./Type/TypeGraph"; +import type { TypeGraph } from "./Type/TypeGraph"; import { type TypeRef, typeRefIndex } from "./Type/TypeRef"; function transformationAttributes( graph: TypeGraph, reconstitutedTargetType: TypeRef, transformer: Transformer, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeAttributes { - const transformation = new Transformation(graph, reconstitutedTargetType, transformer); + const transformation = new Transformation( + graph, + reconstitutedTargetType, + transformer, + ); if (debugPrintTransformations) { - console.log(`transformation for ${typeRefIndex(reconstitutedTargetType)}:`); + console.log( + `transformation for ${typeRefIndex(reconstitutedTargetType)}:`, + ); transformation.debugPrint(); console.log("reverse:"); transformation.reverse.debugPrint(); @@ -58,17 +78,22 @@ function makeEnumTransformer( graph: TypeGraph, enumType: EnumType, stringType: TypeRef, - continuation?: Transformer + continuation?: Transformer, ): Transformer { const sortedCases = Array.from(enumType.cases).sort(); const caseTransformers = sortedCases.map( - c => + (c) => new StringMatchTransformer( graph, stringType, - new StringProducerTransformer(graph, stringType, continuation, c), - c - ) + new StringProducerTransformer( + graph, + stringType, + continuation, + c, + ), + c, + ), ); return new ChoiceTransformer(graph, stringType, caseTransformers); } @@ -78,7 +103,7 @@ function replaceUnion( builder: GraphRewriteBuilder, forwardingRef: TypeRef, transformedTypes: Set, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const graph = builder.typeGraph; @@ -92,10 +117,16 @@ function replaceUnion( // the union must be the target type, so if one already exists, use that // one, otherwise make a new one. if (isPrimitiveStringTypeKind(t.kind)) { - const targetTypeKind = targetTypeKindForTransformedStringTypeKind(t.kind); + const targetTypeKind = targetTypeKindForTransformedStringTypeKind( + t.kind, + ); if (targetTypeKind !== undefined) { const targetTypeMember = union.findMember(targetTypeKind); - additionalAttributes = combineTypeAttributes("union", additionalAttributes, t.getAttributes()); + additionalAttributes = combineTypeAttributes( + "union", + additionalAttributes, + t.getAttributes(), + ); if (targetTypeMember !== undefined) { return builder.reconstituteType(targetTypeMember); } @@ -107,7 +138,10 @@ function replaceUnion( return builder.reconstituteType(t); } - const reconstitutedMembersByKind = mapMapEntries(union.members.entries(), m => [m.kind, reconstituteMember(m)]); + const reconstitutedMembersByKind = mapMapEntries( + union.members.entries(), + (m) => [m.kind, reconstituteMember(m)], + ); const reconstitutedMemberSet = new Set(reconstitutedMembersByKind.values()); const haveUnion = reconstitutedMemberSet.size > 1; @@ -128,17 +162,26 @@ function replaceUnion( return new UnionInstantiationTransformer(graph, memberTypeRef); } - function transformerForKind(kind: TypeKind): DecodingTransformer | undefined { + function transformerForKind( + kind: TypeKind, + ): DecodingTransformer | undefined { const member = union.findMember(kind); if (member === undefined) return undefined; const memberTypeRef = memberForKind(kind); - return new DecodingTransformer(graph, memberTypeRef, consumer(memberTypeRef)); + return new DecodingTransformer( + graph, + memberTypeRef, + consumer(memberTypeRef), + ); } let maybeStringType: TypeRef | undefined = undefined; function getStringType(): TypeRef { if (maybeStringType === undefined) { - maybeStringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); + maybeStringType = builder.getStringType( + emptyTypeAttributes, + StringTypes.unrestricted, + ); } return maybeStringType; @@ -153,21 +196,44 @@ function replaceUnion( } const [min, max] = minMax; - return new MinMaxLengthCheckTransformer(graph, getStringType(), consumer(memberRef), min, max); - } else if (t instanceof EnumType && transformedTypes.has(t)) { - return makeEnumTransformer(graph, t, getStringType(), consumer(memberRef)); - } else { - return new ParseStringTransformer(graph, getStringType(), consumer(memberRef)); + return new MinMaxLengthCheckTransformer( + graph, + getStringType(), + consumer(memberRef), + min, + max, + ); } + if (t instanceof EnumType && transformedTypes.has(t)) { + return makeEnumTransformer( + graph, + t, + getStringType(), + consumer(memberRef), + ); + } + + return new ParseStringTransformer( + graph, + getStringType(), + consumer(memberRef), + ); } - const stringTypes = arraySortByInto(Array.from(union.stringTypeMembers), t => t.kind); + const stringTypes = arraySortByInto( + Array.from(union.stringTypeMembers), + (t) => t.kind, + ); let transformerForString: Transformer | undefined; if (stringTypes.length === 0) { transformerForString = undefined; } else if (stringTypes.length === 1) { const t = stringTypes[0]; - transformerForString = new DecodingTransformer(graph, getStringType(), transformerForStringType(t)); + transformerForString = new DecodingTransformer( + graph, + getStringType(), + transformerForStringType(t), + ); } else { transformerForString = new DecodingTransformer( graph, @@ -175,8 +241,8 @@ function replaceUnion( new ChoiceTransformer( graph, getStringType(), - stringTypes.map(t => defined(transformerForStringType(t))) - ) + stringTypes.map((t) => defined(transformerForStringType(t))), + ), ); } @@ -184,7 +250,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 ?? transformerForMap; @@ -197,13 +263,18 @@ function replaceUnion( transformerForKind("bool"), transformerForString, transformerForKind("array"), - transformerForObject + transformerForObject, + ); + const attributes = transformationAttributes( + graph, + reconstitutedTargetType, + transformer, + debugPrintTransformations, ); - const attributes = transformationAttributes(graph, reconstitutedTargetType, transformer, debugPrintTransformations); return builder.getPrimitiveType( "any", combineTypeAttributes("union", attributes, additionalAttributes), - forwardingRef + forwardingRef, ); } @@ -211,7 +282,7 @@ function replaceArray( arrayType: ArrayType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { const anyType = builder.getPrimitiveType("any"); const anyArrayType = builder.getArrayType(emptyTypeAttributes, anyType); @@ -221,19 +292,19 @@ 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); @@ -243,43 +314,64 @@ function replaceEnum( enumType: EnumType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { - const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); + 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 reconstitutedEnum = builder.getEnumType(enumType.getAttributes(), enumType.cases); const attributes = transformationAttributes( builder.typeGraph, reconstitutedEnum, transformer, - debugPrintTransformations + debugPrintTransformations, + ); + return builder.getStringType( + attributes, + StringTypes.unrestricted, + forwardingRef, ); - return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } function replaceNumber( t: PrimitiveType, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { - const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); + 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 reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); const attributes = transformationAttributes( builder.typeGraph, builder.getPrimitiveType("double", reconstitutedAttributes, undefined), transformer, - debugPrintTransformations + debugPrintTransformations, ); return builder.getPrimitiveType("double", attributes, forwardingRef); } @@ -288,23 +380,38 @@ 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()); - const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); + const reconstitutedAttributes = builder.reconstituteTypeAttributes( + t.getAttributes(), + ); + const stringType = builder.getStringType( + emptyTypeAttributes, + StringTypes.unrestricted, + ); 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, ); - return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } function replaceTransformedStringType( @@ -312,58 +419,102 @@ function replaceTransformedStringType( kind: PrimitiveStringTypeKind, builder: GraphRewriteBuilder, forwardingRef: TypeRef, - debugPrintTransformations: boolean + debugPrintTransformations: boolean, ): TypeRef { - const reconstitutedAttributes = builder.reconstituteTypeAttributes(t.getAttributes()); - const targetTypeKind = withDefault(targetTypeKindForTransformedStringTypeKind(kind), kind); - const stringType = builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); + const reconstitutedAttributes = builder.reconstituteTypeAttributes( + t.getAttributes(), + ); + const targetTypeKind = withDefault( + targetTypeKindForTransformedStringTypeKind(kind), + kind, + ); + const stringType = builder.getStringType( + emptyTypeAttributes, + StringTypes.unrestricted, + ); 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, ); - return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); } -export function makeTransformations(ctx: RunContext, graph: TypeGraph, targetLanguage: TargetLanguage): TypeGraph { - const transformedTypes = setFilter(graph.allTypesUnordered(), t => { +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; const stringMembers = t.stringTypeMembers; if (stringMembers.size <= 1) return false; - return iterableSome(stringMembers, m => targetLanguage.needsTransformerForType(m)); + return iterableSome(stringMembers, (m) => + targetLanguage.needsTransformerForType(m), + ); }); 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); + return replaceUnion( + t, + builder, + forwardingRef, + transformedTypes, + ctx.debugPrintTransformations, + ); } if (t instanceof ArrayType) { - return replaceArray(t, builder, forwardingRef, ctx.debugPrintTransformations); + return replaceArray( + t, + builder, + forwardingRef, + ctx.debugPrintTransformations, + ); } if (t instanceof EnumType) { - return replaceEnum(t, builder, forwardingRef, ctx.debugPrintTransformations); + return replaceEnum( + t, + builder, + forwardingRef, + ctx.debugPrintTransformations, + ); } if (t.kind === "string") { - return replaceString(t as PrimitiveType, builder, forwardingRef, ctx.debugPrintTransformations); + return replaceString( + t as PrimitiveType, + builder, + forwardingRef, + ctx.debugPrintTransformations, + ); } if (isNumberTypeKind(t.kind)) { - return replaceNumber(t as PrimitiveType, builder, forwardingRef, ctx.debugPrintTransformations); + return replaceNumber( + t as PrimitiveType, + builder, + forwardingRef, + ctx.debugPrintTransformations, + ); } if (isPrimitiveStringTypeKind(t.kind)) { @@ -372,20 +523,20 @@ export function makeTransformations(ctx: RunContext, graph: TypeGraph, targetLan t.kind, builder, forwardingRef, - ctx.debugPrintTransformations + ctx.debugPrintTransformations, ); } return panic(`Cannot make transformation for type ${t.kind}`); } - const groups = Array.from(transformedTypes).map(t => [t]); + const groups = Array.from(transformedTypes).map((t) => [t]); return graph.rewrite( "make-transformations", ctx.stringTypeMapping, false, groups, ctx.debugPrintReconstitution, - replace + replace, ); } diff --git a/packages/quicktype-core/src/MarkovChain.ts b/packages/quicktype-core/src/MarkovChain.ts index dec67dc1..cd36d4b5 100644 --- a/packages/quicktype-core/src/MarkovChain.ts +++ b/packages/quicktype-core/src/MarkovChain.ts @@ -94,7 +94,10 @@ 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, []]; @@ -128,8 +131,15 @@ function randomInt(lower: number, upper: number): number { return lower + Math.floor(Math.random() * range); } -export function generate(mc: MarkovChain, state: string, unseenWeight: number): string { - assert(state.length === mc.depth - 1, "State and chain length don't match up"); +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?"); @@ -139,7 +149,9 @@ 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; @@ -185,6 +197,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 28407960..285207c7 100644 --- a/packages/quicktype-core/src/Messages.ts +++ b/packages/quicktype-core/src/Messages.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { type Ref } from "./input/JSONSchemaInput"; -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 } } @@ -10,39 +10,87 @@ export type ErrorProperties = kind: "MiscJSONParseError"; properties: { address: string; description: string; message: string }; } - | { kind: "MiscReadError"; properties: { fileOrURL: string; message: string } } + | { + kind: "MiscReadError"; + properties: { fileOrURL: string; message: string }; + } | { kind: "MiscUnicodeHighSurrogateWithoutLowSurrogate"; properties: {} } - | { kind: "MiscInvalidMinMaxConstraint"; properties: { max: number; min: number } } + | { + 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: "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: "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: "SchemaWrongAccessorEntryArrayLength"; + properties: { operation: string; ref: Ref }; + } | { kind: "SchemaSetOperationCasesIsNotArray"; properties: { cases: any; operation: string; ref: Ref }; } - | { kind: "SchemaMoreThanOneUnionMemberName"; properties: { names: string[] } } + | { + kind: "SchemaMoreThanOneUnionMemberName"; + properties: { names: string[] }; + } | { kind: "SchemaCannotGetTypesFromBoolean"; properties: { ref: string } } - | { kind: "SchemaCannotIndexArrayWithNonNumber"; properties: { actual: string; ref: Ref } } + | { + 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 } } @@ -59,11 +107,17 @@ export type ErrorProperties = | { kind: "DriverCannotInferNameForSchema"; properties: { uri: string } } | { kind: "DriverNoGraphQLQueryGiven"; properties: {} } | { kind: "DriverNoGraphQLSchemaInDir"; properties: { dir: string } } - | { kind: "DriverMoreThanOneGraphQLSchemaInDir"; 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: "DriverCannotMixJSONWithOtherSamples"; + properties: { dir: string }; + } | { kind: "DriverCannotMixNonJSONInputs"; properties: { dir: string } } | { kind: "DriverUnknownDebugOption"; properties: { option: string } } | { kind: "DriverNoLanguageOrExtension"; properties: {} } @@ -71,11 +125,17 @@ export type ErrorProperties = // IR | { kind: "IRNoForwardDeclarableTypeInCycle"; properties: {} } - | { kind: "IRTypeAttributesNotPropagated"; properties: { count: number; indexes: number[] } } + | { + 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 } }; @@ -88,45 +148,62 @@ const errorMessages: ErrorMessages = { InternalError: "Internal error: ${message}", // Misc - MiscJSONParseError: "Syntax error in ${description} JSON ${address}: ${message}", + MiscJSONParseError: + "Syntax error in ${description} JSON ${address}: ${message}", MiscReadError: "Cannot read from file or URL ${fileOrURL}: ${message}", - MiscUnicodeHighSurrogateWithoutLowSurrogate: "Malformed unicode: High surrogate not followed by low surrogate", + MiscUnicodeHighSurrogateWithoutLowSurrogate: + "Malformed unicode: High surrogate not followed by low surrogate", MiscInvalidMinMaxConstraint: "Invalid min-max constraint: ${min}-${max}", // Inference - InferenceJSONReferenceNotRooted: "JSON reference doesn't start with '#/': ${reference}", - InferenceJSONReferenceToUnion: "JSON reference points to a union type: ${reference}", - InferenceJSONReferenceWrongProperty: "JSON reference points to a non-existant property: ${reference}", - InferenceJSONReferenceInvalidArrayIndex: "JSON reference uses invalid array index: ${reference}", + InferenceJSONReferenceNotRooted: + "JSON reference doesn't start with '#/': ${reference}", + InferenceJSONReferenceToUnion: + "JSON reference points to a union type: ${reference}", + InferenceJSONReferenceWrongProperty: + "JSON reference points to a non-existant property: ${reference}", + InferenceJSONReferenceInvalidArrayIndex: + "JSON reference uses invalid array index: ${reference}", // JSON Schema input SchemaArrayIsInvalidSchema: "An array is not a valid JSON Schema at ${ref}", SchemaNullIsInvalidSchema: "null is not a valid JSON Schema at ${ref}", - SchemaRefMustBeString: "$ref must be a string, but is an ${actual} at ${ref}", + SchemaRefMustBeString: + "$ref must be a string, but is an ${actual} at ${ref}", SchemaAdditionalTypesForbidRequired: "Can't have non-specified required properties but forbidden additionalTypes at ${ref}", - SchemaNoTypeSpecified: "JSON Schema must specify at least one type 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}', - SchemaInvalidJSONSchemaType: "Value of type ${type} is not valid JSON Schema 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}", - SchemaRequiredElementMustBeString: "`required` must contain only strings, but it has ${element}, at ${ref}", - SchemaTypeMustBeStringOrStringArray: "`type` must be string or array of strings, but is ${actual}", - SchemaTypeElementMustBeString: "`type` must contain only strings, but it has ${element}", - SchemaArrayItemsMustBeStringOrArray: "Array items must be an array or an object, but is ${actual}", + SchemaRequiredElementMustBeString: + "`required` must contain only strings, but it has ${element}, at ${ref}", + SchemaTypeMustBeStringOrStringArray: + "`type` must be string or array of strings, but is ${actual}", + SchemaTypeElementMustBeString: + "`type` must contain only strings, but it has ${element}", + SchemaArrayItemsMustBeStringOrArray: + "Array items must be an array or an object, but is ${actual}", SchemaIDMustHaveAddress: "$id ${id} doesn't have an address at ${ref}", SchemaWrongAccessorEntryArrayLength: "Accessor entry array must have the same number of entries as the ${operation} at ${ref}", - SchemaSetOperationCasesIsNotArray: "${operation} cases must be an array, but is ${cases}, at ${ref}", - SchemaMoreThanOneUnionMemberName: "More than one name given for union member: ${names}", + SchemaSetOperationCasesIsNotArray: + "${operation} cases must be an array, but is ${cases}, at ${ref}", + SchemaMoreThanOneUnionMemberName: + "More than one name given for union member: ${names}", SchemaCannotGetTypesFromBoolean: "Schema value to get top-level types from must be an object, but is boolean, at ${ref}", SchemaCannotIndexArrayWithNonNumber: "Trying to index array in schema with key that is not a number, but is ${actual} at ${ref}", - SchemaIndexNotInArray: "Index ${index} out of range of schema array at ${ref}", + SchemaIndexNotInArray: + "Index ${index} out of range of schema array at ${ref}", SchemaKeyNotInObject: "Key ${key} not in schema object at ${ref}", - SchemaFetchError: "Could not fetch schema ${address}, referred to from ${base}", + SchemaFetchError: + "Could not fetch schema ${address}, referred to from ${base}", SchemaFetchErrorTopLevel: "Could not fetch top-level schema ${address}", SchemaFetchErrorAdditional: "Could not fetch additional schema ${address}", @@ -136,19 +213,26 @@ const errorMessages: ErrorMessages = { // Driver DriverUnknownSourceLanguage: "Unknown source language ${lang}", DriverUnknownOutputLanguage: "Unknown output language ${lang}", - DriverMoreThanOneInputGiven: "More than one input given for top-level ${topLevel}", + DriverMoreThanOneInputGiven: + "More than one input given for top-level ${topLevel}", DriverCannotInferNameForSchema: "Cannot infer name for schema ${uri}", - DriverNoGraphQLQueryGiven: "Please specify at least one GraphQL query as input", + DriverNoGraphQLQueryGiven: + "Please specify at least one GraphQL query as input", DriverNoGraphQLSchemaInDir: "No GraphQL schema in ${dir}", - DriverMoreThanOneGraphQLSchemaInDir: "More than one GraphQL schema in ${dir}", - DriverSourceLangMustBeGraphQL: "If a GraphQL schema is specified, the source language must be GraphQL", - DriverGraphQLSchemaNeeded: "Please specify a GraphQL schema with --graphql-schema or --graphql-introspect", + DriverMoreThanOneGraphQLSchemaInDir: + "More than one GraphQL schema in ${dir}", + DriverSourceLangMustBeGraphQL: + "If a GraphQL schema is specified, the source language must be GraphQL", + DriverGraphQLSchemaNeeded: + "Please specify a GraphQL schema with --graphql-schema or --graphql-introspect", DriverInputFileDoesNotExist: "Input file ${filename} does not exist", DriverCannotMixJSONWithOtherSamples: "Cannot mix JSON samples with JSON Schems, GraphQL, or TypeScript in input subdirectory ${dir}", - DriverCannotMixNonJSONInputs: "Cannot mix JSON Schema, GraphQL, and TypeScript in an input subdirectory ${dir}", + DriverCannotMixNonJSONInputs: + "Cannot mix JSON Schema, GraphQL, and TypeScript in an input subdirectory ${dir}", DriverUnknownDebugOption: "Unknown debug option ${option}", - DriverNoLanguageOrExtension: "Please specify a language (--lang) or an output file extension", + DriverNoLanguageOrExtension: + "Please specify a language (--lang) or an output file extension", DriverCLIOptionParsingFailed: "Option parsing failed: ${message}", // IR @@ -156,36 +240,47 @@ const errorMessages: ErrorMessages = { "Cannot resolve cycle because it doesn't contain types that can be forward declared", IRTypeAttributesNotPropagated: "Type attributes for ${count} types were not carried over to the new graph: ${indexes}", - IRNoEmptyUnions: "Trying to make an empty union - do you have an impossible type in your schema?", + IRNoEmptyUnions: + "Trying to make an empty union - do you have an impossible type in your schema?", // Rendering RendererUnknownOptionValue: "Unknown value ${value} for option ${name}", // TypeScript input - TypeScriptCompilerError: "TypeScript error: ${message}" + TypeScriptCompilerError: "TypeScript error: ${message}", }; -export type ErrorPropertiesForKind = - Extract extends { properties: infer P } ? P : never; +export type ErrorPropertiesForKind = Extract< + ErrorProperties, + { kind: K } +> extends { properties: infer P } + ? P + : never; export class QuickTypeError extends Error { public constructor( public readonly errorMessage: string, public readonly messageName: string, public userMessage: string, - public readonly properties: StringMap + public readonly properties: StringMap, ) { super(userMessage); } } -export function messageError(kind: Kind, properties: ErrorPropertiesForKind): never { +export function messageError( + kind: Kind, + properties: ErrorPropertiesForKind, +): never { const message = errorMessages[kind]; let userMessage: string = message; for (const [name, value] of Object.entries(properties as StringMap)) { let valueString = ""; - if (typeof value === "object" && typeof value?.toString === "function") { + if ( + typeof value === "object" && + typeof value?.toString === "function" + ) { valueString = value.toString(); } else if (typeof value?.message === "string") { valueString = value.message; @@ -196,13 +291,18 @@ export function messageError(kind: Kind, properties: Er userMessage = userMessage.replace("${" + name + "}", valueString); } - throw new QuickTypeError(message, kind, userMessage, properties as StringMap); + throw new QuickTypeError( + message, + kind, + userMessage, + properties as StringMap, + ); } export function messageAssert( assertion: boolean, kind: Kind, - properties: ErrorPropertiesForKind + properties: ErrorPropertiesForKind, ): 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 cc98c50f..73df1ed7 100644 --- a/packages/quicktype-core/src/Naming.ts +++ b/packages/quicktype-core/src/Naming.ts @@ -10,7 +10,7 @@ import { setGroupBy, setMap, setUnion, - setUnionInto + setUnionInto, } from "collection-utils"; import { assert, defined, panic } from "./support/Support"; @@ -28,7 +28,7 @@ export class Namespace { _name: string, parent: Namespace | undefined, forbiddenNamespaces: Iterable, - additionalForbidden: Iterable + additionalForbidden: Iterable, ) { this.forbiddenNamespaces = new Set(forbiddenNamespaces); this.additionalForbidden = new Set(additionalForbidden); @@ -51,7 +51,10 @@ export class Namespace { public get forbiddenNameds(): ReadonlySet { // FIXME: cache - return setUnion(this.additionalForbidden, ...Array.from(this.forbiddenNamespaces).map(ns => ns.members)); + return setUnion( + this.additionalForbidden, + ...Array.from(this.forbiddenNamespaces).map((ns) => ns.members), + ); } public add(named: TName): TName { @@ -83,7 +86,7 @@ export class Namer { public constructor( public readonly name: string, public readonly nameStyle: NameStyle, - public prefixes: string[] + public prefixes: string[], ) { this._prefixes = new Set(prefixes); } @@ -93,16 +96,19 @@ export class Namer { public assignNames( names: ReadonlyMap, forbiddenNamesIterable: Iterable, - namesToAssignIterable: Iterable + namesToAssignIterable: Iterable, ): ReadonlyMap { const forbiddenNames = new Set(forbiddenNamesIterable); const namesToAssign = Array.from(namesToAssignIterable); - assert(namesToAssign.length > 0, "Number of names can't be less than 1"); + assert( + namesToAssign.length > 0, + "Number of names can't be less than 1", + ); const allAssignedNames = new Map(); - let namesToPrefix: Name[] = []; + const namesToPrefix: Name[] = []; for (const name of namesToAssign) { const proposedNames = name.proposeUnstyledNames(names); const namingFunction = name.namingFunction; @@ -110,13 +116,20 @@ export class Namer { // any of the other names and that isn't already forbidden. const maybeUniqueName = iterableFind( proposedNames, - proposed => + (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); - const assigned = name.nameAssignments(forbiddenNames, styledName); + const assigned = name.nameAssignments( + forbiddenNames, + styledName, + ); if (assigned !== null) { mapMergeInto(allAssignedNames, assigned); setUnionInto(forbiddenNames, assigned.values()); @@ -129,10 +142,12 @@ export class Namer { namesToPrefix.push(name); } - let prefixes = this._prefixes.values(); + const prefixes = this._prefixes.values(); let suffixNumber = 1; for (const name of namesToPrefix) { - const originalName: string = defined(iterableFirst(name.proposeUnstyledNames(names))); + const originalName: string = defined( + iterableFirst(name.proposeUnstyledNames(names)), + ); for (;;) { let nameToTry: string; const { done, value: prefix } = prefixes.next(); @@ -144,7 +159,10 @@ export class Namer { } const styledName = name.namingFunction.nameStyle(nameToTry); - const assigned = name.nameAssignments(forbiddenNames, styledName); + const assigned = name.nameAssignments( + forbiddenNames, + styledName, + ); if (assigned === null) continue; mapMergeInto(allAssignedNames, assigned); setUnionInto(forbiddenNames, assigned.values()); @@ -169,7 +187,7 @@ const funPrefixes = [ "Magenta", "Frisky", "Mischievous", - "Braggadocious" + "Braggadocious", ]; export function funPrefixNamer(name: string, nameStyle: NameStyle): Namer { @@ -187,7 +205,7 @@ export abstract class Name { // If a Named is fixed, the namingFunction is undefined. public constructor( private readonly _namingFunction: Namer | undefined, - public readonly order: number + public readonly order: number, ) {} public addAssociate(associate: AssociatedName): void { @@ -205,7 +223,9 @@ export abstract class Name { } // Must return at least one proposal. The proposals are considered in order. - public abstract proposeUnstyledNames(names: ReadonlyMap): ReadonlySet; + public abstract proposeUnstyledNames( + names: ReadonlyMap, + ): ReadonlySet; public firstProposedName(names: ReadonlyMap): string { return defined(iterableFirst(this.proposeUnstyledNames(names))); @@ -213,7 +233,7 @@ export abstract class Name { public nameAssignments( forbiddenNames: ReadonlySet, - assignedName: string + assignedName: string, ): ReadonlyMap | null { if (forbiddenNames.has(assignedName)) return null; const assignments = new Map([[this, assignedName]]); @@ -248,7 +268,9 @@ export class FixedName extends Name { return this._fixedName; } - public proposeUnstyledNames(_?: ReadonlyMap): ReadonlySet { + public proposeUnstyledNames( + _?: ReadonlyMap, + ): ReadonlySet { return panic("Only fixedName should be called on FixedName."); } } @@ -256,7 +278,11 @@ export class FixedName extends Name { export class SimpleName extends Name { private readonly _unstyledNames: ReadonlySet; - public constructor(unstyledNames: Iterable, namingFunction: Namer, order: number) { + public constructor( + unstyledNames: Iterable, + namingFunction: Namer, + order: number, + ) { super(namingFunction, order); this._unstyledNames = new Set(unstyledNames); } @@ -265,7 +291,9 @@ export class SimpleName extends Name { return []; } - public proposeUnstyledNames(_?: ReadonlyMap): ReadonlySet { + public proposeUnstyledNames( + _?: ReadonlyMap, + ): ReadonlySet { return this._unstyledNames; } } @@ -274,7 +302,7 @@ export class AssociatedName extends Name { public constructor( private readonly _sponsor: Name, order: number, - public readonly getName: (sponsorName: string) => string + public readonly getName: (sponsorName: string) => string, ) { super(undefined, order); } @@ -294,11 +322,13 @@ export class DependencyName extends Name { 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[] = []; - _proposeUnstyledName(n => { + _proposeUnstyledName((n) => { dependencies.push(n); return "0xDEADBEEF"; }); @@ -309,17 +339,25 @@ export class DependencyName extends Name { return Array.from(this._dependencies); } - public 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"); + this._proposeUnstyledName((n) => { + assert( + this._dependencies.has(n), + "DependencyName proposer is not pure", + ); return defined(names.get(n)); - }) + }), ]); } } -export function keywordNamespace(name: string, keywords: readonly 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)); @@ -328,8 +366,15 @@ export function keywordNamespace(name: string, keywords: readonly string[]): Nam return ns; } -function allNamespacesRecursively(namespaces: Iterable): ReadonlySet { - return setUnion(namespaces, ...Array.from(setMap(namespaces, ns => allNamespacesRecursively(ns.children)))); +function allNamespacesRecursively( + namespaces: Iterable, +): ReadonlySet { + return setUnion( + namespaces, + ...Array.from( + setMap(namespaces, (ns) => allNamespacesRecursively(ns.children)), + ), + ); } class NamingContext { @@ -353,7 +398,9 @@ class NamingContext { } public areForbiddensFullyNamed(namespace: Namespace): boolean { - return iterableEvery(namespace.forbiddenNameds, n => this._names.has(n)); + return iterableEvery(namespace.forbiddenNameds, (n) => + this._names.has(n), + ); } public isConflicting(namedNamespace: Namespace, proposed: string): boolean { @@ -362,7 +409,10 @@ class NamingContext { if (namedsForProposed === undefined) return false; // The name is assigned, but it might still not be forbidden. for (const n of namedsForProposed) { - if (namedNamespace.members.has(n) || namedNamespace.forbiddenNameds.has(n)) { + if ( + namedNamespace.members.has(n) || + namedNamespace.forbiddenNameds.has(n) + ) { return true; } } @@ -372,7 +422,10 @@ class NamingContext { 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`); + assert( + !this.isConflicting(namedNamespace, name), + `Assigned name "${name}" conflicts`, + ); this._names.set(named, name); let namedsForName = this._namedsForName.get(name); if (namedsForName === undefined) { @@ -385,7 +438,9 @@ class NamingContext { } // Naming algorithm -export function assignNames(rootNamespaces: Iterable): ReadonlyMap { +export function assignNames( + rootNamespaces: Iterable, +): ReadonlyMap { const ctx = new NamingContext(rootNamespaces); // Assign all fixed names. @@ -402,9 +457,11 @@ export function assignNames(rootNamespaces: Iterable): ReadonlyMap ctx.areForbiddensFullyNamed(ns)); - const readyNamespace = iterableFind(unfinishedNamespaces, ns => - iterableSome(ns.members, member => ctx.isReadyToBeNamed(member)) + const unfinishedNamespaces = setFilter(ctx.namespaces, (ns) => + ctx.areForbiddensFullyNamed(ns), + ); + const readyNamespace = iterableFind(unfinishedNamespaces, (ns) => + iterableSome(ns.members, (member) => ctx.isReadyToBeNamed(member)), ); if (readyNamespace === undefined) { @@ -412,31 +469,48 @@ export function assignNames(rootNamespaces: Iterable): ReadonlyMap ctx.names.get(n)); + const allForbiddenNames = setUnion( + readyNamespace.members, + readyNamespace.forbiddenNameds, + ); + const forbiddenNames = setFilterMap(allForbiddenNames, (n) => + ctx.names.get(n), + ); // 2. From low order to high order, sort those names into sets where all // members of a set propose the same name and have the same naming // function. for (;;) { - const allReadyNames = setFilter(readyNamespace.members, member => ctx.isReadyToBeNamed(member)); - const minOrderName = iterableMinBy(allReadyNames, n => n.order); + const allReadyNames = setFilter(readyNamespace.members, (member) => + ctx.isReadyToBeNamed(member), + ); + const minOrderName = iterableMinBy(allReadyNames, (n) => n.order); if (minOrderName === undefined) break; const minOrder = minOrderName.order; - const readyNames = setFilter(allReadyNames, n => n.order === minOrder); + const readyNames = setFilter( + allReadyNames, + (n) => n.order === minOrder, + ); // It would be nice if we had tuples, then we wouldn't have to do this in // two steps. - const byNamingFunction = setGroupBy(readyNames, n => n.namingFunction); + const byNamingFunction = setGroupBy( + readyNames, + (n) => n.namingFunction, + ); for (const [namer, namedsForNamingFunction] of byNamingFunction) { - const byProposed = setGroupBy(namedsForNamingFunction, n => - n.namingFunction.nameStyle(n.firstProposedName(ctx.names)) + const byProposed = setGroupBy(namedsForNamingFunction, (n) => + n.namingFunction.nameStyle(n.firstProposedName(ctx.names)), ); for (const [, nameds] of byProposed) { // 3. Use each set's naming function to name its members. - const names = namer.assignNames(ctx.names, forbiddenNames, nameds); + const names = namer.assignNames( + ctx.names, + forbiddenNames, + nameds, + ); for (const [name, assigned] of names) { ctx.assign(name, readyNamespace, assigned); } diff --git a/packages/quicktype-core/src/Renderer.ts b/packages/quicktype-core/src/Renderer.ts index dc8543af..f151da0b 100644 --- a/packages/quicktype-core/src/Renderer.ts +++ b/packages/quicktype-core/src/Renderer.ts @@ -2,21 +2,35 @@ import { iterableEnumerate } from "collection-utils"; 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 { + 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 TypeGraph } from "./Type/TypeGraph"; +import type { TargetLanguage } from "./TargetLanguage"; +import type { TypeGraph } from "./Type/TypeGraph"; export interface RenderResult { names: ReadonlyMap; sources: ReadonlyMap; } -export type BlankLinePosition = "none" | "interposing" | "leading" | "leading-and-interposing"; +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] }; } @@ -24,7 +38,10 @@ function getBlankLineConfig(cfg: BlankLineConfig): { count: number; position: Bl 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++) { @@ -100,13 +117,18 @@ class EmitContext { } public containsItem(item: Sourcelike): boolean { - const existingItem = this._currentEmitTarget.find((value: Sourcelike) => item === value); + const existingItem = this._currentEmitTarget.find( + (value: Sourcelike) => item === value, + ); return existingItem !== undefined; } public ensureBlankLine(numBlankLines: number): void { if (this._preventBlankLine) return; - this._numBlankLinesNeeded = Math.max(this._numBlankLinesNeeded, numBlankLines); + this._numBlankLinesNeeded = Math.max( + this._numBlankLinesNeeded, + numBlankLines, + ); } public preventBlankLine(): void { @@ -116,7 +138,7 @@ class EmitContext { public changeIndent(offset: number): void { if (this._lastNewline === undefined) { - return panic("Cannot change indent for the first line"); + panic("Cannot change indent for the first line"); } this._lastNewline.indentationChange += offset; @@ -138,7 +160,7 @@ export abstract class Renderer { public constructor( protected readonly targetLanguage: TargetLanguage, - renderContext: RenderContext + renderContext: RenderContext, ) { this.typeGraph = renderContext.typeGraph; this.leadingComments = renderContext.leadingComments; @@ -223,7 +245,10 @@ export abstract class Renderer { const oldEmitContext = this._emitContext; this._emitContext = new EmitContext(); emitter(); - assert(!this._emitContext.isNested, "emit context not restored correctly"); + assert( + !this._emitContext.isNested, + "emit context not restored correctly", + ); const source = this._emitContext.source; this._emitContext = oldEmitContext; return source; @@ -235,7 +260,10 @@ export abstract class Renderer { } } - protected 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)); @@ -247,7 +275,9 @@ export abstract class Renderer { protected emitTable = (tableArray: Sourcelike[][]): void => { if (tableArray.length === 0) return; - const table = tableArray.map(r => r.map(sl => sourcelikeToSource(sl))); + const table = tableArray.map((r) => + r.map((sl) => sourcelikeToSource(sl)), + ); this._emitContext.emitItem({ kind: "table", table }); this._emitContext.emitNewline(); }; @@ -256,12 +286,21 @@ export abstract class Renderer { this._emitContext.changeIndent(offset); } - protected 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)) { const position = - items.length === 1 ? "only" : onFirst ? "first" : i === items.length - 1 ? "last" : "middle"; + items.length === 1 + ? "only" + : onFirst + ? "first" + : i === items.length - 1 + ? "last" + : "middle"; emitter(v, position); onFirst = false; } @@ -271,7 +310,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) => { @@ -290,12 +329,21 @@ export abstract class Renderer { 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); - const leading = ["leading", "leading-and-interposing"].includes(position); - return this.forEach(iterable, interposing ? count : 0, leading ? count : 0, emitter); + 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, + ); } // FIXME: make protected once JavaDateTimeRenderer is refactored @@ -314,7 +362,9 @@ export abstract class Renderer { protected initializeEmitContextForFilename(filename: string): void { if (this._finishedEmitContexts.has(filename.toLowerCase())) { - const existingEmitContext = this._finishedEmitContexts.get(filename.toLowerCase()); + const existingEmitContext = this._finishedEmitContexts.get( + filename.toLowerCase(), + ); if (existingEmitContext !== undefined) { this._emitContext = existingEmitContext; } @@ -324,7 +374,7 @@ export abstract class Renderer { 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.`, ); } @@ -332,7 +382,10 @@ export abstract class Renderer { this._finishedFiles.set(filename, source); // [Michael Fey (@MrRooni), 2019-5-9] We save the current EmitContext for possible reuse later. We put it into the map with a lowercased version of the key so we can do a case-insensitive lookup later. The reason we lowercase it is because some schema (looking at you keyword-unions.schema) define objects of the same name with different casing. BOOL vs. bool, for example. - this._finishedEmitContexts.set(filename.toLowerCase(), this._emitContext); + this._finishedEmitContexts.set( + filename.toLowerCase(), + this._emitContext, + ); this._emitContext = new EmitContext(); } diff --git a/packages/quicktype-core/src/RendererOptions/index.ts b/packages/quicktype-core/src/RendererOptions/index.ts index c8a9f66e..3c61dcbd 100644 --- a/packages/quicktype-core/src/RendererOptions/index.ts +++ b/packages/quicktype-core/src/RendererOptions/index.ts @@ -1,6 +1,6 @@ import { messageError } from "../Messages"; import { assert } from "../support/Support"; -import { type FixMeOptionsType, type NoInfer } from "../types"; +import type { LanguageName, RendererOptions } from "../types"; import type { OptionDefinition, OptionKind, OptionValues } from "./types"; @@ -15,7 +15,10 @@ export abstract class Option { public constructor(definition: OptionDefinition) { this.definition = definition; - assert(definition.kind !== undefined, "Renderer option kind must be defined"); + assert( + definition.kind !== undefined, + "Renderer option kind must be defined", + ); } public get name(): Name { @@ -34,11 +37,14 @@ export abstract class Option { } } -export function getOptionValues>>( +export function getOptionValues< + const Options extends Record>, + Lang extends LanguageName, +>( options: Options, - untypedOptionValues: FixMeOptionsType + untypedOptionValues: RendererOptions, ): OptionValues { - const optionValues: FixMeOptionsType = {}; + const optionValues: Record = {}; for (const [key, option] of Object.entries(options)) { const value = option.getValue(untypedOptionValues); @@ -62,13 +68,18 @@ export class BooleanOption extends Option { * @param defaultValue The default value. * @param kind Whether it's a primary or secondary option. */ - public constructor(name: Name, description: string, defaultValue: boolean, kind: OptionKind = "primary") { + public constructor( + name: Name, + description: string, + defaultValue: boolean, + kind: OptionKind = "primary", + ) { super({ name, kind, type: Boolean, description, - defaultValue + defaultValue, }); } @@ -78,15 +89,15 @@ export class BooleanOption extends Option { } { const negated = Object.assign({}, this.definition, { name: `no-${this.name}`, - defaultValue: !this.definition.defaultValue + defaultValue: !this.definition.defaultValue, }); const display = Object.assign({}, this.definition, { name: `[no-]${this.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], }; } @@ -109,9 +120,9 @@ export class BooleanOption extends Option { if (this.definition.defaultValue) { return (value && !negated) as boolean; - } else { - return (value || !negated) as boolean; } + + return (value || !negated) as boolean; } } @@ -121,7 +132,7 @@ export class StringOption extends Option { description: string, typeLabel: string, defaultValue: string, - kind: OptionKind = "primary" + kind: OptionKind = "primary", ) { const definition = { name, @@ -129,17 +140,19 @@ export class StringOption extends Option { type: String, description, typeLabel, - defaultValue + defaultValue, }; super(definition); } } -// FIXME: use const generics here export class EnumOption< Name extends string, - EnumMap extends Record, - EnumKey extends Extract = Extract + const EnumMap extends Record, + EnumKey extends Extract = Extract< + keyof EnumMap, + string + >, > extends Option { private readonly _values: EnumMap; @@ -148,7 +161,7 @@ export class EnumOption< description: string, values: EnumMap, defaultValue: NoInfer, - kind: OptionKind = "primary" + kind: OptionKind = "primary", ) { const definition = { name, @@ -156,21 +169,24 @@ export class EnumOption< type: String, description, typeLabel: Object.keys(values).join("|"), - defaultValue + defaultValue, }; super(definition); this._values = values; } - public getEnumValue(name: Key): EnumMap[Key] { + public getEnumValue(name: Key): EnumMap[Key] { if (!name) { const defaultKey = this.definition.defaultValue as NonNullable; return this._values[defaultKey]; } if (!(name in this._values)) { - return messageError("RendererUnknownOptionValue", { value: name, name: this.name }); + return messageError("RendererUnknownOptionValue", { + value: name, + name: this.name, + }); } return this._values[name]; diff --git a/packages/quicktype-core/src/RendererOptions/types.ts b/packages/quicktype-core/src/RendererOptions/types.ts index 79fe7f19..cc8ff70e 100644 --- a/packages/quicktype-core/src/RendererOptions/types.ts +++ b/packages/quicktype-core/src/RendererOptions/types.ts @@ -19,16 +19,29 @@ export interface OptionDefinition { typeLabel?: string; } -export type OptionName = O extends Option ? Name : never; -export type OptionValue = - O extends EnumOption - ? EnumMap[EnumKey] - : O extends Option - ? Value - : never; +export type OptionName = O extends Option + ? Name + : never; +export type OptionValue = O extends EnumOption< + string, + infer EnumMap, + infer EnumKey +> + ? EnumMap[EnumKey] + : O extends Option + ? Value + : never; -export type OptionKey = O extends EnumOption, infer EnumKey> ? EnumKey : O; +export type OptionKey = O extends EnumOption< + string, + Record, + infer EnumKey +> + ? EnumKey + : O; // FIXME: Merge these and use camelCase user-facing keys (v24) -export type OptionMap = { [K in keyof T as OptionName]: OptionKey }; // user-facing, keys are `name` property of Option, values are the available input type +export type OptionMap = { + [K in keyof T as OptionName]: OptionKey; +}; // user-facing, keys are `name` property of Option, values are the available input type export type OptionValues = { [K in keyof T]: OptionValue }; // internal, keys are keys of `_Options` object in each language file diff --git a/packages/quicktype-core/src/Run.ts b/packages/quicktype-core/src/Run.ts index f415aeb8..85a48c84 100644 --- a/packages/quicktype-core/src/Run.ts +++ b/packages/quicktype-core/src/Run.ts @@ -1,13 +1,10 @@ import { mapFirst } from "collection-utils"; import { initTypeNames } from "./attributes/TypeNames"; -import { gatherNames } from "./GatherNames"; import { InputData } from "./input/Inputs"; import * as targetLanguages from "./language/All"; import type { RendererOptions } from "./language/options.types"; import type { LanguageName } from "./language/types"; -import { makeTransformations } from "./MakeTransformations"; -import { messageError } from "./Messages"; import { combineClasses } from "./rewrites/CombineClasses"; import { expandStrings } from "./rewrites/ExpandStrings"; import { flattenStrings } from "./rewrites/FlattenStrings"; @@ -15,18 +12,37 @@ import { flattenUnions } from "./rewrites/FlattenUnions"; import { inferMaps } from "./rewrites/InferMaps"; import { replaceObjectType } from "./rewrites/ReplaceObjectType"; import { resolveIntersections } from "./rewrites/ResolveIntersections"; -import { type Annotation, type Location, type SerializedRenderResult, type Span } from "./Source"; -import { type Comment } from "./support/Comments"; +import type { Comment } from "./support/Comments"; import { assert } from "./support/Support"; -import { type MultiFileRenderResult, type TargetLanguage } from "./TargetLanguage"; -import { type TransformedStringTypeKind } from "./Type"; -import { TypeBuilder } from "./Type/TypeBuilder"; -import { type StringTypeMapping } from "./Type/TypeBuilderUtils"; -import { TypeGraph } from "./Type/TypeGraph"; -import { noneToAny, optionalToNullable, removeIndirectionIntersections } from "./Type/TypeGraphUtils"; -import { type FixMeOptionsType } from "./types"; -export function getTargetLanguage(nameOrInstance: LanguageName | TargetLanguage): TargetLanguage { +import { gatherNames } from "./GatherNames"; +import { + type InferenceFlags, + defaultInferenceFlags, + inferenceFlagNames, + inferenceFlags, +} from "./Inference"; +import { makeTransformations } from "./MakeTransformations"; +import { messageError } from "./Messages"; +import type { + Annotation, + Location, + SerializedRenderResult, + Span, +} from "./Source"; +import type { MultiFileRenderResult, TargetLanguage } from "./TargetLanguage"; +import { TypeBuilder } from "./Type/TypeBuilder"; +import type { StringTypeMapping } from "./Type/TypeBuilderUtils"; +import { TypeGraph } from "./Type/TypeGraph"; +import { + noneToAny, + optionalToNullable, + removeIndirectionIntersections, +} from "./Type/TypeGraphUtils"; + +export function getTargetLanguage( + nameOrInstance: LanguageName | TargetLanguage, +): TargetLanguage { if (typeof nameOrInstance === "object") { return nameOrInstance; } @@ -36,88 +52,11 @@ export function getTargetLanguage(nameOrInstance: LanguageName | TargetLanguage) return language; } - return messageError("DriverUnknownOutputLanguage", { lang: nameOrInstance }); + return messageError("DriverUnknownOutputLanguage", { + lang: nameOrInstance, + }); } -export interface InferenceFlag { - description: string; - explanation: string; - negationDescription: string; - order: number; - stringType?: TransformedStringTypeKind; -} - -export const inferenceFlagsObject = { - /** Whether to infer map types from JSON data */ - inferMaps: { - description: "Detect maps", - negationDescription: "Don't infer maps, always use classes", - explanation: "Infer maps when object keys look like map keys.", - 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 - }, - /** Whether to convert UUID strings to UUID objects */ - inferUuids: { - description: "Detect UUIDs", - 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 - }, - /** Whether to assume that JSON strings that look like dates are dates */ - inferDateTimes: { - description: "Detect dates & times", - negationDescription: "Don't infer dates or times", - explanation: "Infer dates from strings (partial support).", - stringType: "date-time" as TransformedStringTypeKind, - 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.', - stringType: "integer-string" as TransformedStringTypeKind, - 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.', - stringType: "bool-string" as TransformedStringTypeKind, - order: 6 - }, - /** Combine similar classes. This doesn't apply to classes from a schema, only from inference. */ - combineClasses: { - description: "Merge similar classes", - negationDescription: "Don't combine similar classes", - explanation: - "Combine classes with significantly overlapping properties,\ntreating contingent properties as nullable.", - order: 7 - }, - /** Whether to treat $ref as references within JSON */ - ignoreJsonRefs: { - description: "Don't treat $ref as a reference in JSON", - 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 - } -}; -export type InferenceFlagName = keyof typeof inferenceFlagsObject; -export const inferenceFlagNames = Object.getOwnPropertyNames(inferenceFlagsObject) as InferenceFlagName[]; -export const inferenceFlags: { [F in InferenceFlagName]: InferenceFlag } = inferenceFlagsObject; - -export type InferenceFlags = { [F in InferenceFlagName]: boolean }; - /** * The options type for the main quicktype entry points, * `quicktypeMultiFile` and `quicktype`. @@ -193,7 +132,7 @@ const defaultOptions: NonInferenceOptions = { debugPrintGatherNames: false, debugPrintTransformations: false, debugPrintTimes: false, - debugPrintSchemaResolving: false + debugPrintSchemaResolving: false, }; export interface RunContext { @@ -213,30 +152,17 @@ interface GraphInputs { typeBuilder: TypeBuilder; } -function makeDefaultInferenceFlags(): InferenceFlags { - const flags = {} as InferenceFlags; - for (const flag of inferenceFlagNames) { - flags[flag] = true; - } - - return flags; -} - -export const defaultInferenceFlags = makeDefaultInferenceFlags(); - class Run implements RunContext { private readonly _options: Options; public constructor(options: Partial) { // We must not overwrite defaults with undefined values, which // we sometimes get. - this._options = Object.assign({}, defaultOptions, defaultInferenceFlags); - for (const k of Object.getOwnPropertyNames(options)) { - const v = (options as FixMeOptionsType)[k]; - if (v !== undefined) { - (this._options as FixMeOptionsType)[k] = v; - } - } + this._options = Object.fromEntries( + Object.entries( + Object.assign({}, defaultOptions, defaultInferenceFlags), + ).map(([k, v]) => [k, options[k as keyof typeof options] ?? v]), + ) as Required; } public get stringTypeMapping(): StringTypeMapping { @@ -289,17 +215,27 @@ class Run implements RunContext { private makeGraphInputs(): GraphInputs { const targetLanguage = getTargetLanguage(this._options.lang); const stringTypeMapping = this.stringTypeMapping; - const conflateNumbers = !targetLanguage.supportsUnionsWithBothNumberTypes; + const conflateNumbers = + !targetLanguage.supportsUnionsWithBothNumberTypes; const typeBuilder = new TypeBuilder( stringTypeMapping, this._options.alphabetizeProperties, this._options.allPropertiesOptional, this._options.checkProvenance, - false + false, + ); + typeBuilder.typeGraph = new TypeGraph( + typeBuilder, + 0, + this._options.checkProvenance, ); - typeBuilder.typeGraph = new TypeGraph(typeBuilder, 0, this._options.checkProvenance); - return { targetLanguage, stringTypeMapping, conflateNumbers, typeBuilder }; + return { + targetLanguage, + stringTypeMapping, + conflateNumbers, + typeBuilder, + }; } private async makeGraph(allInputs: InputData): Promise { @@ -313,8 +249,8 @@ class Run implements RunContext { graphInputs.typeBuilder, this._options.inferMaps, this._options.inferEnums, - this._options.fixedTopLevels - ) + this._options.fixedTopLevels, + ), ); return this.processGraph(allInputs, graphInputs); @@ -329,15 +265,23 @@ 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 { - const { targetLanguage, stringTypeMapping, conflateNumbers, typeBuilder } = graphInputs; + private processGraph( + allInputs: InputData, + graphInputs: GraphInputs, + ): TypeGraph { + const { + targetLanguage, + stringTypeMapping, + conflateNumbers, + typeBuilder, + } = graphInputs; let graph = typeBuilder.finish(); if (this._options.debugPrintGraph) { @@ -347,11 +291,17 @@ class Run implements RunContext { const debugPrintReconstitution = this.debugPrintReconstitution; - if (typeBuilder.didAddForwardingIntersection || !this._options.ignoreJsonRefs) { - this.time( - "remove indirection intersections", - () => (graph = removeIndirectionIntersections(graph, stringTypeMapping, debugPrintReconstitution)) - ); + if ( + typeBuilder.didAddForwardingIntersection || + !this._options.ignoreJsonRefs + ) { + this.time("remove indirection intersections", () => { + graph = removeIndirectionIntersections( + graph, + stringTypeMapping, + debugPrintReconstitution, + ); + }); } let unionsDone = false; @@ -360,88 +310,93 @@ class Run implements RunContext { do { const graphBeforeRewrites = graph; if (!intersectionsDone) { - this.time( - "resolve intersections", - () => - ([graph, intersectionsDone] = resolveIntersections( - graph, - stringTypeMapping, - debugPrintReconstitution - )) - ); + this.time("resolve intersections", () => { + [graph, intersectionsDone] = resolveIntersections( + graph, + stringTypeMapping, + debugPrintReconstitution, + ); + }); } if (!unionsDone) { - this.time( - "flatten unions", - () => - ([graph, unionsDone] = flattenUnions( - graph, - stringTypeMapping, - conflateNumbers, - true, - debugPrintReconstitution - )) - ); + this.time("flatten unions", () => { + [graph, unionsDone] = flattenUnions( + graph, + stringTypeMapping, + conflateNumbers, + true, + debugPrintReconstitution, + ); + }); } if (graph === graphBeforeRewrites) { - assert(intersectionsDone && unionsDone, "Graph didn't change but we're not done"); + assert( + intersectionsDone && unionsDone, + "Graph didn't change but we're not done", + ); } } while (!intersectionsDone || !unionsDone); } - this.time( - "replace object type", - () => - (graph = replaceObjectType( + this.time("replace object type", () => { + graph = replaceObjectType( + graph, + stringTypeMapping, + conflateNumbers, + targetLanguage.supportsFullObjectType, + debugPrintReconstitution, + ); + }); + do { + this.time("flatten unions", () => { + [graph, unionsDone] = flattenUnions( graph, stringTypeMapping, conflateNumbers, - targetLanguage.supportsFullObjectType, - debugPrintReconstitution - )) - ); - do { - this.time( - "flatten unions", - () => - ([graph, unionsDone] = flattenUnions( - graph, - stringTypeMapping, - conflateNumbers, - false, - debugPrintReconstitution - )) - ); + false, + 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; } else { - this.time( - "combine classes cleanup", - () => - (graph = combineClasses( - this, - combinedGraph, - this._options.alphabetizeProperties, - false, - true, - debugPrintReconstitution - )) - ); + this.time("combine classes cleanup", () => { + graph = combineClasses( + this, + combinedGraph, + this._options.alphabetizeProperties, + false, + true, + debugPrintReconstitution, + ); + }); } } 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; @@ -451,52 +406,76 @@ 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( - "flatten unions", - () => - ([graph, unionsDone] = flattenUnions( - graph, - stringTypeMapping, - conflateNumbers, - false, - debugPrintReconstitution - )) + const enumInference = allInputs.needSchemaProcessing + ? "all" + : this._options.inferEnums + ? "infer" + : "none"; + this.time("expand strings", () => { + graph = expandStrings(this, graph, enumInference); + }); + this.time("flatten unions", () => { + [graph, unionsDone] = flattenUnions( + graph, + stringTypeMapping, + conflateNumbers, + false, + debugPrintReconstitution, + ); + }); + assert( + unionsDone, + "We should only have to flatten unions once after expanding strings", ); - 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)) - ); - } - - this.time("none to any", () => (graph = noneToAny(graph, stringTypeMapping, debugPrintReconstitution))); - if (!targetLanguage.supportsOptionalClassProperties) { - this.time( - "optional to nullable", - () => (graph = optionalToNullable(graph, stringTypeMapping, debugPrintReconstitution)) - ); - } - - this.time("fixed point", () => (graph = graph.rewriteFixedPoint(false, debugPrintReconstitution))); - - this.time("make transformations", () => (graph = makeTransformations(this, graph, targetLanguage))); - - this.time( - "flatten unions", - () => - ([graph, unionsDone] = flattenUnions( + this.time("flatten strings", () => { + graph = flattenStrings( graph, stringTypeMapping, - conflateNumbers, - false, - debugPrintReconstitution - )) + debugPrintReconstitution, + ); + }); + } + + this.time("none to any", () => { + graph = noneToAny( + graph, + stringTypeMapping, + debugPrintReconstitution, + ); + }); + if (!targetLanguage.supportsOptionalClassProperties) { + this.time("optional to nullable", () => { + graph = optionalToNullable( + graph, + stringTypeMapping, + debugPrintReconstitution, + ); + }); + } + + this.time("fixed point", () => { + graph = graph.rewriteFixedPoint(false, debugPrintReconstitution); + }); + + this.time("make transformations", () => { + graph = makeTransformations(this, graph, targetLanguage); + }); + + this.time("flatten unions", () => { + [graph, unionsDone] = flattenUnions( + graph, + stringTypeMapping, + conflateNumbers, + false, + debugPrintReconstitution, + ); + }); + assert( + unionsDone, + "We should only have to flatten unions once after making transformations", ); - assert(unionsDone, "We should only have to flatten unions once after making transformations"); // Sometimes we combine classes in ways that will the order come out // differently compared to what it would be from the equivalent schema, @@ -505,17 +484,23 @@ class Run implements RunContext { // FIXME: We don't actually have to do this if any of the above graph // rewrites did anything. We could just check whether the current graph // is different from the one we started out with. - this.time( - "GC", - () => (graph = graph.garbageCollect(this._options.alphabetizeProperties, debugPrintReconstitution)) - ); + this.time("GC", () => { + 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(); @@ -525,9 +510,9 @@ class Run implements RunContext { } private makeSimpleTextResult(lines: string[]): MultiFileRenderResult { - return new Map([[this._options.outputFilename, { lines, annotations: [] }]] as Array< - [string, SerializedRenderResult] - >); + return new Map([ + [this._options.outputFilename, { lines, annotations: [] }], + ] as Array<[string, SerializedRenderResult]>); } private preRun(): MultiFileRenderResult | [InputData, TargetLanguage] { @@ -536,14 +521,26 @@ class Run implements RunContext { const targetLanguage = getTargetLanguage(this._options.lang); const inputData = this._options.inputData; - const needIR = inputData.needIR || !targetLanguage.names.includes("schema"); + const needIR = + inputData.needIR || !targetLanguage.names.includes("schema"); - const schemaString = needIR ? undefined : inputData.singleStringSchemaSource(); + const schemaString = needIR + ? undefined + : inputData.singleStringSchemaSource(); if (schemaString !== undefined) { - const lines = JSON.stringify(JSON.parse(schemaString), undefined, 4).split("\n"); + const lines = JSON.stringify( + JSON.parse(schemaString), + undefined, + 4, + ).split("\n"); lines.push(""); const srr = { lines, annotations: [] }; - return new Map([[this._options.outputFilename, srr] as [string, SerializedRenderResult]]); + return new Map([ + [this._options.outputFilename, srr] as [ + string, + SerializedRenderResult, + ], + ]); } return [inputData, targetLanguage]; @@ -575,7 +572,10 @@ 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.", ""]); } @@ -586,7 +586,7 @@ class Run implements RunContext { this._options.alphabetizeProperties, this._options.leadingComments, this._options.rendererOptions, - this._options.indentation + this._options.indentation, ); } } @@ -597,11 +597,15 @@ 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(); } @@ -610,7 +614,10 @@ function offsetLocation(loc: Location, lineOffset: number): Location { } function offsetSpan(span: Span, lineOffset: number): Span { - return { start: offsetLocation(span.start, lineOffset), end: offsetLocation(span.end, lineOffset) }; + return { + start: offsetLocation(span.start, lineOffset), + end: offsetLocation(span.end, lineOffset), + }; } /** @@ -618,7 +625,9 @@ 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) { @@ -634,7 +643,10 @@ export function combineRenderResults(result: MultiFileRenderResult): SerializedR 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), + })), ); } @@ -649,7 +661,9 @@ 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 fcf00454..5286d8ab 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 { type AnnotationData } from "./Annotation"; +import type { AnnotationData } from "./Annotation"; import { Name } from "./Naming"; import { repeatString } from "./support/Strings"; import { assert, assertNever, defined, panic } from "./support/Support"; @@ -69,7 +69,7 @@ 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), + ), }; } @@ -99,11 +99,15 @@ 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 +115,14 @@ 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 +147,10 @@ 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; @@ -157,7 +167,8 @@ function sourceLineLength(source: Source, names: ReadonlyMap): num case "name": return defined(names.get(source.named)).length; case "modified": - return serializeRenderResult(source, names, "").lines.join("\n").length; + return serializeRenderResult(source, names, "").lines.join("\n") + .length; default: return assertNever(source); } @@ -166,7 +177,7 @@ function sourceLineLength(source: Source, names: ReadonlyMap): num export function serializeRenderResult( rootSource: Source, names: ReadonlyMap, - indentation: string + indentation: string, ): SerializedRenderResult { let indent = 0; let indentNeeded = 0; @@ -217,12 +228,20 @@ export function serializeRenderResult( const t = source.table; const numRows = t.length; if (numRows === 0) break; - const widths = t.map(l => l.map(s => sourceLineLength(s, names))); - const numColumns = defined(iterableMax(t.map(l => l.length))); + const widths = t.map((l) => + l.map((s) => sourceLineLength(s, names)), + ); + const numColumns = defined(iterableMax(t.map((l) => l.length))); if (numColumns === 0) break; const columnWidths: number[] = []; for (let i = 0; i < numColumns; i++) { - columnWidths.push(defined(iterableMax(widths.map(l => withDefault(l[i], 0))))); + columnWidths.push( + defined( + iterableMax( + widths.map((l) => withDefault(l[i], 0)), + ), + ), + ); } for (let y = 0; y < numRows; y++) { @@ -231,11 +250,16 @@ export function serializeRenderResult( const rowWidths = defined(widths[y]); for (let x = 0; x < numColumns; x++) { const colWidth = columnWidths[x]; - const src = withDefault(row[x], { kind: "text", text: "" }); + const src = withDefault(row[x], { + kind: "text", + text: "", + }); const srcWidth = withDefault(rowWidths[x], 0); serializeToStringArray(src); if (x < numColumns - 1 && srcWidth < colWidth) { - currentLine.push(repeatString(" ", colWidth - srcWidth)); + currentLine.push( + repeatString(" ", colWidth - srcWidth), + ); } } @@ -250,7 +274,10 @@ export function serializeRenderResult( const start = currentLocation(); serializeToStringArray(source.source); const end = currentLocation(); - annotations.push({ annotation: source.annotation, span: { start, end } }); + annotations.push({ + annotation: source.annotation, + span: { start, end }, + }); break; case "name": assert(names.has(source.named), "No name for Named"); @@ -259,8 +286,15 @@ export function serializeRenderResult( break; case "modified": indentIfNeeded(); - const serialized = serializeRenderResult(source.source, names, indentation).lines; - assert(serialized.length === 1, "Cannot modify more than one line."); + const serialized = serializeRenderResult( + source.source, + names, + indentation, + ).lines; + assert( + serialized.length === 1, + "Cannot modify more than one line.", + ); currentLine.push(source.modifier(serialized[0])); break; default: @@ -282,7 +316,10 @@ 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]); diff --git a/packages/quicktype-core/src/TargetLanguage.ts b/packages/quicktype-core/src/TargetLanguage.ts index 3c8933c7..84fce85c 100644 --- a/packages/quicktype-core/src/TargetLanguage.ts +++ b/packages/quicktype-core/src/TargetLanguage.ts @@ -2,15 +2,15 @@ import { mapMap } from "collection-utils"; import { ConvenienceRenderer } from "./ConvenienceRenderer"; import { type DateTimeRecognizer, DefaultDateTimeRecognizer } from "./DateTime"; -import { type RenderContext, type Renderer } from "./Renderer"; -import { type Option, type OptionDefinition } from "./RendererOptions"; +import type { RenderContext, Renderer } from "./Renderer"; +import type { Option, OptionDefinition } from "./RendererOptions"; import { type SerializedRenderResult, serializeRenderResult } from "./Source"; -import { type Comment } from "./support/Comments"; +import type { Comment } from "./support/Comments"; import { defined } from "./support/Support"; -import { type Type } from "./Type/Type"; -import { type StringTypeMapping } from "./Type/TypeBuilderUtils"; -import { type TypeGraph } from "./Type/TypeGraph"; -import { type FixMeOptionsType } from "./types"; +import type { Type } from "./Type/Type"; +import type { StringTypeMapping } from "./Type/TypeBuilderUtils"; +import type { TypeGraph } from "./Type/TypeGraph"; +import type { LanguageName, RendererOptions } from "./types"; export type MultiFileRenderResult = ReadonlyMap; @@ -20,7 +20,9 @@ export interface LanguageConfig { readonly names: readonly string[]; } -export abstract class TargetLanguage { +export abstract class TargetLanguage< + Config extends LanguageConfig = LanguageConfig, +> { public readonly displayName: Config["displayName"]; public readonly names: Config["names"]; @@ -36,7 +38,7 @@ export abstract class TargetLanguage>; public get optionDefinitions(): Array> { - return Object.values(this.getOptions()).map(o => o.definition); + return Object.values(this.getOptions()).map((o) => o.definition); } public get cliOptionDefinitions(): { @@ -57,15 +59,18 @@ export abstract class TargetLanguage( + renderContext: RenderContext, + optionValues: RendererOptions, + ): Renderer; - public renderGraphAndSerialize( + public renderGraphAndSerialize( typeGraph: TypeGraph, givenOutputFilename: string, alphabetizeProperties: boolean, leadingComments: Comment[] | undefined, - rendererOptions: FixMeOptionsType, - indentation?: string + rendererOptions: RendererOptions, + indentation?: string, ): MultiFileRenderResult { if (indentation === undefined) { indentation = this.defaultIndentation; @@ -78,7 +83,9 @@ export abstract class TargetLanguage serializeRenderResult(s, renderResult.names, defined(indentation))); + return mapMap(renderResult.sources, (s) => + serializeRenderResult(s, renderResult.names, defined(indentation)), + ); } protected get defaultIndentation(): string { diff --git a/packages/quicktype-core/src/Transformers.ts b/packages/quicktype-core/src/Transformers.ts index 1cb2e016..3827c92c 100644 --- a/packages/quicktype-core/src/Transformers.ts +++ b/packages/quicktype-core/src/Transformers.ts @@ -6,14 +6,20 @@ import { definedMapWithDefault, hashCodeOf, hashString, - setUnionInto + setUnionInto, } from "collection-utils"; import { TypeAttributeKind } from "./attributes/TypeAttributes"; -import { type BaseGraphRewriteBuilder } from "./GraphRewriting"; +import type { BaseGraphRewriteBuilder } from "./GraphRewriting"; import { assert, indentationString, panic } from "./support/Support"; -import { EnumType, PrimitiveType, type Type, type TypeKind, UnionType } from "./Type"; -import { type TypeGraph } from "./Type/TypeGraph"; +import { + EnumType, + PrimitiveType, + type Type, + type TypeKind, + UnionType, +} from "./Type"; +import type { TypeGraph } from "./Type/TypeGraph"; import { type TypeRef, derefTypeRef } from "./Type/TypeRef"; function debugStringForType(t: Type): string { @@ -26,14 +32,14 @@ function debugStringForType(t: Type): string { } function getNumberOfNodes(xfer: Transformer | undefined): number { - return definedMapWithDefault(xfer, 0, x => x.getNumberOfNodes()); + return definedMapWithDefault(xfer, 0, (x) => x.getNumberOfNodes()); } export abstract class Transformer { public constructor( public readonly kind: string, protected readonly graph: TypeGraph, - public readonly sourceTypeRef: TypeRef + public readonly sourceTypeRef: TypeRef, ) {} public get sourceType(): Type { @@ -51,9 +57,14 @@ export abstract class Transformer { public abstract get canFail(): boolean; - public abstract reverse(targetTypeRef: TypeRef, continuationTransformer: Transformer | undefined): Transformer; + public abstract reverse( + targetTypeRef: TypeRef, + continuationTransformer: Transformer | undefined, + ): Transformer; - public abstract reconstitute(builder: TBuilder): Transformer; + public abstract reconstitute( + builder: TBuilder, + ): Transformer; public equals(other: T): boolean { return this.sourceTypeRef === other.sourceTypeRef; @@ -82,7 +93,7 @@ export abstract class ProducerTransformer extends Transformer { kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, - public readonly consumer: Transformer | undefined + public readonly consumer: Transformer | undefined, ) { super(kind, graph, sourceTypeRef); } @@ -119,13 +130,16 @@ export abstract class MatchTransformer extends Transformer { kind: string, graph: TypeGraph, sourceTypeRef: TypeRef, - public readonly transformer: Transformer + public readonly transformer: Transformer, ) { super(kind, graph, sourceTypeRef); } public getChildren(): Set { - return setUnionInto(super.getChildren(), this.transformer.getChildren()); + return setUnionInto( + super.getChildren(), + this.transformer.getChildren(), + ); } public getNumberOfNodes(): number { @@ -149,7 +163,11 @@ export abstract class MatchTransformer extends Transformer { } export class DecodingTransformer extends ProducerTransformer { - public constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + public constructor( + graph: TypeGraph, + sourceTypeRef: TypeRef, + consumer: Transformer | undefined, + ) { super("decode", graph, sourceTypeRef, consumer); } @@ -157,26 +175,33 @@ export class DecodingTransformer extends ProducerTransformer { return false; } - public 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"); + return panic( + "Reversing a decoding transformer cannot have a continuation", + ); } if (this.consumer === undefined) { return new EncodingTransformer(this.graph, targetTypeRef); - } else { - return this.consumer.reverse( - targetTypeRef, - new EncodingTransformer(this.graph, this.consumer.sourceTypeRef) - ); } + + return this.consumer.reverse( + targetTypeRef, + new EncodingTransformer(this.graph, this.consumer.sourceTypeRef), + ); } - public 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)), ); } @@ -195,12 +220,20 @@ export class EncodingTransformer extends Transformer { return false; } - public reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + public reverse( + _targetTypeRef: TypeRef, + _continuationTransformer: Transformer | undefined, + ): Transformer { return panic("Can't reverse encoding transformer"); } - public reconstitute(builder: TBuilder): Transformer { - return new EncodingTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); + public reconstitute( + builder: TBuilder, + ): Transformer { + return new EncodingTransformer( + builder.typeGraph, + builder.reconstituteTypeRef(this.sourceTypeRef), + ); } public equals(other: T): boolean { @@ -216,7 +249,7 @@ export class ArrayDecodingTransformer extends ProducerTransformer { sourceTypeRef: TypeRef, consumer: Transformer | undefined, private readonly _itemTargetTypeRef: TypeRef, - public readonly itemTransformer: Transformer + public readonly itemTransformer: Transformer, ) { super("decode-array", graph, sourceTypeRef, consumer); } @@ -228,7 +261,9 @@ export class ArrayDecodingTransformer extends ProducerTransformer { } public getNumberOfNodes(): number { - return super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes(); + return ( + super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes() + ); } public get canFail(): boolean { @@ -239,40 +274,50 @@ export class ArrayDecodingTransformer extends ProducerTransformer { return derefTypeRef(this._itemTargetTypeRef, this.graph); } - public 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"); + return panic( + "Reversing a decoding transformer cannot have a continuation", + ); } - const itemTransformer = this.itemTransformer.reverse(this._itemTargetTypeRef, undefined); + const itemTransformer = this.itemTransformer.reverse( + this._itemTargetTypeRef, + undefined, + ); if (this.consumer === undefined) { return new ArrayEncodingTransformer( this.graph, targetTypeRef, this.itemTransformer.sourceTypeRef, - itemTransformer - ); - } else { - return this.consumer.reverse( - targetTypeRef, - new ArrayEncodingTransformer( - this.graph, - this.consumer.sourceTypeRef, - this.itemTransformer.sourceTypeRef, - itemTransformer - ) + itemTransformer, ); } + + return this.consumer.reverse( + targetTypeRef, + new ArrayEncodingTransformer( + this.graph, + this.consumer.sourceTypeRef, + this.itemTransformer.sourceTypeRef, + itemTransformer, + ), + ); } - public 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)), + definedMap(this.consumer, (xfer) => xfer.reconstitute(builder)), builder.reconstituteTypeRef(this._itemTargetTypeRef), - this.itemTransformer.reconstitute(builder) + this.itemTransformer.reconstitute(builder), ); } @@ -286,7 +331,8 @@ export class ArrayDecodingTransformer extends ProducerTransformer { 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; + if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) + return false; return this.itemTransformer.equals(other.itemTransformer); } @@ -301,7 +347,7 @@ export class ArrayEncodingTransformer extends Transformer { graph: TypeGraph, sourceTypeRef: TypeRef, private readonly _itemTargetTypeRef: TypeRef, - public readonly itemTransformer: Transformer + public readonly itemTransformer: Transformer, ) { super("encode-array", graph, sourceTypeRef); } @@ -313,7 +359,9 @@ export class ArrayEncodingTransformer extends Transformer { } public getNumberOfNodes(): number { - return super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes(); + return ( + super.getNumberOfNodes() + this.itemTransformer.getNumberOfNodes() + ); } public get canFail(): boolean { @@ -324,16 +372,21 @@ export class ArrayEncodingTransformer extends Transformer { return derefTypeRef(this._itemTargetTypeRef, this.graph); } - public reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + public reverse( + _targetTypeRef: TypeRef, + _continuationTransformer: Transformer | undefined, + ): Transformer { return panic("Can't reverse array encoding transformer"); } - public 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), ); } @@ -346,7 +399,8 @@ export class ArrayEncodingTransformer extends Transformer { 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; + if (!areEqual(this._itemTargetTypeRef, other._itemTargetTypeRef)) + return false; return this.itemTransformer.equals(other.itemTransformer); } @@ -360,14 +414,17 @@ export class ChoiceTransformer extends Transformer { public constructor( graph: TypeGraph, sourceTypeRef: TypeRef, - public readonly transformers: readonly Transformer[] + public readonly transformers: readonly Transformer[], ) { super("choice", graph, sourceTypeRef); - assert(transformers.length > 0, "Choice must have at least one transformer"); + assert( + transformers.length > 0, + "Choice must have at least one transformer", + ); } public getChildren(): Set { - let children = super.getChildren(); + const children = super.getChildren(); for (const xfer of this.transformers) { setUnionInto(children, xfer.getChildren()); } @@ -385,21 +442,41 @@ export class ChoiceTransformer extends Transformer { } public get canFail(): boolean { - return this.transformers.some(xfer => xfer.canFail); + return this.transformers.some((xfer) => xfer.canFail); } - 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[]; + 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[]; const first = memberMatchers[0]; - if (memberMatchers.every(xfer => first.memberType.equals(xfer.memberType))) { - const subTransformers = memberMatchers.map(xfer => xfer.transformer); + if ( + memberMatchers.every((xfer) => + first.memberType.equals(xfer.memberType), + ) + ) { + const subTransformers = memberMatchers.map( + (xfer) => xfer.transformer, + ); return new UnionMemberMatchTransformer( this.graph, targetTypeRef, - new ChoiceTransformer(this.graph, subTransformers[0].sourceTypeRef, subTransformers), - first.memberTypeRef + new ChoiceTransformer( + this.graph, + subTransformers[0].sourceTypeRef, + subTransformers, + ), + first.memberTypeRef, ); } } @@ -407,11 +484,13 @@ export class ChoiceTransformer extends Transformer { return new ChoiceTransformer(this.graph, targetTypeRef, transformers); } - public 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)), ); } @@ -443,7 +522,7 @@ export class DecodingChoiceTransformer extends Transformer { public readonly boolTransformer: Transformer | undefined, public readonly stringTransformer: Transformer | undefined, public readonly arrayTransformer: Transformer | undefined, - public readonly objectTransformer: Transformer | undefined + public readonly objectTransformer: Transformer | undefined, ) { super("decoding-choice", graph, sourceTypeRef); } @@ -467,7 +546,7 @@ export class DecodingChoiceTransformer extends Transformer { } public getChildren(): Set { - let children = super.getChildren(); + const children = super.getChildren(); for (const xfer of this.transformers) { setUnionInto(children, xfer.getChildren()); } @@ -488,14 +567,17 @@ export class DecodingChoiceTransformer extends Transformer { return false; } - public 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(); + const transformers = new Map(); + const memberMatchTransformers = new Map(); function addCase(reversed: Transformer): void { if (reversed instanceof UnionMemberMatchTransformer) { @@ -544,7 +626,7 @@ export class DecodingChoiceTransformer extends Transformer { function filter(xfers: Transformer[]): Transformer[] { assert(xfers.length > 0, "Must have at least one transformer"); - const nonfailing = xfers.filter(xfer => { + const nonfailing = xfers.filter((xfer) => { // For member match transformers we're deciding between // multiple that match against the same member, so the fact // that the match can fail is not important, since if it fails @@ -552,34 +634,48 @@ export class DecodingChoiceTransformer extends Transformer { // its continuation can fail. if (xfer instanceof UnionMemberMatchTransformer) { return !xfer.transformer.canFail; - } else { - return !xfer.canFail; } + + return !xfer.canFail; }); if (nonfailing.length === 0) return xfers; const smallest = arraySortByInto( - nonfailing.map(x => [x.getNumberOfNodes(), x] as [number, Transformer]), - ([c, _]) => c + nonfailing.map( + (x) => [x.getNumberOfNodes(), x] as [number, Transformer], + ), + ([c, _]) => c, )[0][1]; return [smallest]; } this.transformers.forEach(reverseAndAdd); - const allTransformers = Array.from(transformers.values()).concat(Array.from(memberMatchTransformers.values())); - const resultingTransformers = ([] as Transformer[]).concat(...allTransformers.map(filter)); + const allTransformers = Array.from(transformers.values()).concat( + Array.from(memberMatchTransformers.values()), + ); + const resultingTransformers = ([] as Transformer[]).concat( + ...allTransformers.map(filter), + ); // No choice needed if there's only one if (resultingTransformers.length === 1) { return resultingTransformers[0]; } - return new ChoiceTransformer(this.graph, targetTypeRef, resultingTransformers); + return new ChoiceTransformer( + this.graph, + targetTypeRef, + resultingTransformers, + ); } - public reconstitute(builder: TBuilder): Transformer { - function reconstitute(xf: Transformer | undefined): Transformer | undefined { + public reconstitute( + builder: TBuilder, + ): Transformer { + function reconstitute( + xf: Transformer | undefined, + ): Transformer | undefined { if (xf === undefined) return undefined; return xf.reconstitute(builder); } @@ -593,20 +689,27 @@ export class DecodingChoiceTransformer extends Transformer { reconstitute(this.boolTransformer), reconstitute(this.stringTransformer), reconstitute(this.arrayTransformer), - reconstitute(this.objectTransformer) + reconstitute(this.objectTransformer), ); } 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; - if (!areEqual(this.integerTransformer, other.integerTransformer)) return false; - if (!areEqual(this.doubleTransformer, other.doubleTransformer)) return false; - if (!areEqual(this.boolTransformer, other.boolTransformer)) return false; - if (!areEqual(this.stringTransformer, other.stringTransformer)) return false; - if (!areEqual(this.arrayTransformer, other.arrayTransformer)) return false; - if (!areEqual(this.objectTransformer, other.objectTransformer)) return false; + if (!areEqual(this.nullTransformer, other.nullTransformer)) + return false; + if (!areEqual(this.integerTransformer, other.integerTransformer)) + return false; + if (!areEqual(this.doubleTransformer, other.doubleTransformer)) + return false; + if (!areEqual(this.boolTransformer, other.boolTransformer)) + return false; + if (!areEqual(this.stringTransformer, other.stringTransformer)) + return false; + if (!areEqual(this.arrayTransformer, other.arrayTransformer)) + return false; + if (!areEqual(this.objectTransformer, other.objectTransformer)) + return false; return true; } @@ -634,7 +737,7 @@ export class UnionMemberMatchTransformer extends MatchTransformer { graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, - public readonly memberTypeRef: TypeRef + public readonly memberTypeRef: TypeRef, ) { super("union-member-match", graph, sourceTypeRef, transformer); } @@ -642,7 +745,9 @@ export class UnionMemberMatchTransformer extends MatchTransformer { 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"); + return panic( + "The source of a union member match transformer must be a union type", + ); } return t; @@ -660,16 +765,21 @@ export class UnionMemberMatchTransformer extends MatchTransformer { return super.getChildren().add(this.memberType); } - public reverse(_targetTypeRef: TypeRef, _continuationTransformer: Transformer | undefined): Transformer { + public reverse( + _targetTypeRef: TypeRef, + _continuationTransformer: Transformer | undefined, + ): Transformer { return panic("Can't reverse union member match transformer"); } - public 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), ); } @@ -697,15 +807,20 @@ export class StringMatchTransformer extends MatchTransformer { graph: TypeGraph, sourceTypeRef: TypeRef, transformer: Transformer, - public readonly stringCase: string + public readonly stringCase: string, ) { super("string-match", graph, sourceTypeRef, transformer); } 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"); + 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; @@ -715,24 +830,29 @@ export class StringMatchTransformer extends MatchTransformer { return true; } - public 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, + ), ); } - public 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, ); } @@ -761,16 +881,31 @@ export class UnionInstantiationTransformer extends Transformer { return false; } - public 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"); + return panic( + "Union instantiation transformer reverse must have a continuation", + ); } - return new UnionMemberMatchTransformer(this.graph, targetTypeRef, continuationTransformer, this.sourceTypeRef); + return new UnionMemberMatchTransformer( + this.graph, + targetTypeRef, + continuationTransformer, + this.sourceTypeRef, + ); } - public reconstitute(builder: TBuilder): Transformer { - return new UnionInstantiationTransformer(builder.typeGraph, builder.reconstituteTypeRef(this.sourceTypeRef)); + public reconstitute( + builder: TBuilder, + ): Transformer { + return new UnionInstantiationTransformer( + builder.typeGraph, + builder.reconstituteTypeRef(this.sourceTypeRef), + ); } public equals(other: T): boolean { @@ -787,7 +922,7 @@ export class StringProducerTransformer extends ProducerTransformer { graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined, - public readonly result: string + public readonly result: string, ) { super("string-producer", graph, sourceTypeRef, consumer); } @@ -796,32 +931,44 @@ export class StringProducerTransformer extends ProducerTransformer { return false; } - public 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"); + return panic( + "Reversing a string producer transformer must have a continuation", + ); } if (this.consumer === undefined) { - return new StringMatchTransformer(this.graph, targetTypeRef, continuationTransformer, this.result); - } else { - return this.consumer.reverse( + return new StringMatchTransformer( + this.graph, targetTypeRef, - new StringMatchTransformer( - this.graph, - this.consumer.sourceTypeRef, - continuationTransformer, - this.result - ) + continuationTransformer, + this.result, ); } + + return this.consumer.reverse( + targetTypeRef, + new StringMatchTransformer( + this.graph, + this.consumer.sourceTypeRef, + continuationTransformer, + this.result, + ), + ); } - public 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 + definedMap(this.consumer, (xfer) => xfer.reconstitute(builder)), + this.result, ); } @@ -842,7 +989,11 @@ export class StringProducerTransformer extends ProducerTransformer { } export class ParseStringTransformer extends ProducerTransformer { - public constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + public constructor( + graph: TypeGraph, + sourceTypeRef: TypeRef, + consumer: Transformer | undefined, + ) { super("parse-string", graph, sourceTypeRef, consumer); } @@ -850,22 +1001,35 @@ export class ParseStringTransformer extends ProducerTransformer { return true; } - public 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( + return new StringifyTransformer( + this.graph, targetTypeRef, - new StringifyTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer) + continuationTransformer, ); } + + return this.consumer.reverse( + targetTypeRef, + new StringifyTransformer( + this.graph, + this.consumer.sourceTypeRef, + continuationTransformer, + ), + ); } - public 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)), ); } @@ -876,7 +1040,11 @@ export class ParseStringTransformer extends ProducerTransformer { } export class StringifyTransformer extends ProducerTransformer { - public constructor(graph: TypeGraph, sourceTypeRef: TypeRef, consumer: Transformer | undefined) { + public constructor( + graph: TypeGraph, + sourceTypeRef: TypeRef, + consumer: Transformer | undefined, + ) { super("stringify", graph, sourceTypeRef, consumer); } @@ -884,22 +1052,35 @@ export class StringifyTransformer extends ProducerTransformer { return false; } - public 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( + return new ParseStringTransformer( + this.graph, targetTypeRef, - new ParseStringTransformer(this.graph, this.consumer.sourceTypeRef, continuationTransformer) + continuationTransformer, ); } + + return this.consumer.reverse( + targetTypeRef, + new ParseStringTransformer( + this.graph, + this.consumer.sourceTypeRef, + continuationTransformer, + ), + ); } - public 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)), ); } @@ -915,7 +1096,7 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { sourceTypeRef: TypeRef, consumer: Transformer | undefined, public readonly minLength: number | undefined, - public readonly maxLength: number | undefined + public readonly maxLength: number | undefined, ) { super("min-max-length-check", graph, sourceTypeRef, consumer); } @@ -924,36 +1105,41 @@ export class MinMaxLengthCheckTransformer extends ProducerTransformer { return true; } - public 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 - ); - } else { - return this.consumer.reverse( - targetTypeRef, - new MinMaxLengthCheckTransformer( - this.graph, - this.consumer.sourceTypeRef, - continuationTransformer, - this.minLength, - this.maxLength - ) + this.maxLength, ); } + + return this.consumer.reverse( + targetTypeRef, + new MinMaxLengthCheckTransformer( + this.graph, + this.consumer.sourceTypeRef, + continuationTransformer, + this.minLength, + this.maxLength, + ), + ); } - public 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)), + definedMap(this.consumer, (xfer) => xfer.reconstitute(builder)), this.minLength, - this.maxLength + this.maxLength, ); } @@ -973,7 +1159,7 @@ export class MinMaxValueTransformer extends ProducerTransformer { sourceTypeRef: TypeRef, consumer: Transformer | undefined, public readonly minimum: number | undefined, - public readonly maximum: number | undefined + public readonly maximum: number | undefined, ) { super("min-max-value-check", graph, sourceTypeRef, consumer); } @@ -982,43 +1168,50 @@ export class MinMaxValueTransformer extends ProducerTransformer { return true; } - public 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 - ); - } else { - return this.consumer.reverse( - targetTypeRef, - new MinMaxValueTransformer( - this.graph, - this.consumer.sourceTypeRef, - continuationTransformer, - this.minimum, - this.maximum - ) + this.maximum, ); } + + return this.consumer.reverse( + targetTypeRef, + new MinMaxValueTransformer( + this.graph, + this.consumer.sourceTypeRef, + continuationTransformer, + this.minimum, + this.maximum, + ), + ); } - public 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)), + definedMap(this.consumer, (xfer) => xfer.reconstitute(builder)), this.minimum, - this.maximum + this.maximum, ); } public equals(other: T): boolean { if (!super.equals(other)) return false; return ( - other instanceof MinMaxValueTransformer && this.minimum === other.minimum && this.maximum === other.maximum + other instanceof MinMaxValueTransformer && + this.minimum === other.minimum && + this.maximum === other.maximum ); } } @@ -1027,7 +1220,7 @@ export class Transformation { public constructor( private readonly _graph: TypeGraph, private readonly _targetTypeRef: TypeRef, - public readonly transformer: Transformer + public readonly transformer: Transformer, ) {} public get sourceType(): Type { @@ -1042,7 +1235,7 @@ export class Transformation { return new Transformation( this._graph, this.transformer.sourceTypeRef, - this.transformer.reverse(this._targetTypeRef, undefined) + this.transformer.reverse(this._targetTypeRef, undefined), ); } @@ -1050,17 +1243,22 @@ export class Transformation { return this.transformer.getChildren().add(this.targetType); } - public 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), ); } public equals(other: T): boolean { if (!(other instanceof Transformation)) return false; - return this._targetTypeRef === other._targetTypeRef && this.transformer.equals(other.transformer); + return ( + this._targetTypeRef === other._targetTypeRef && + this.transformer.equals(other.transformer) + ); } public hashCode(): number { @@ -1094,7 +1292,7 @@ class TransformationTypeAttributeKind extends TypeAttributeKind public reconstitute( builder: TBuilder, - xf: Transformation + xf: Transformation, ): Transformation { return xf.reconstitute(builder); } @@ -1104,16 +1302,22 @@ class TransformationTypeAttributeKind extends TypeAttributeKind } } -export const transformationTypeAttributeKind: TypeAttributeKind = new TransformationTypeAttributeKind(); +export const transformationTypeAttributeKind: TypeAttributeKind = + new TransformationTypeAttributeKind(); export function transformationForType(t: Type): Transformation | undefined { - return transformationTypeAttributeKind.tryGetInAttributes(t.getAttributes()); + return transformationTypeAttributeKind.tryGetInAttributes( + t.getAttributes(), + ); } export function followTargetType(t: Type): Type { for (;;) { const xf = transformationForType(t); - if (xf === undefined) return t; + if (xf === undefined) { + return t; + } + t = xf.targetType; } } diff --git a/packages/quicktype-core/src/Type/ProvenanceTypeAttributeKind.ts b/packages/quicktype-core/src/Type/ProvenanceTypeAttributeKind.ts index 60e65674..2b4ece43 100644 --- a/packages/quicktype-core/src/Type/ProvenanceTypeAttributeKind.ts +++ b/packages/quicktype-core/src/Type/ProvenanceTypeAttributeKind.ts @@ -2,7 +2,7 @@ import { setUnionManyInto } from "collection-utils"; import { TypeAttributeKind } from "../attributes/TypeAttributes"; -import { type TypeKind } from "./TransformedStringType"; +import type { TypeKind } from "./TransformedStringType"; // FIXME: Don't infer provenance. All original types should be present in // non-inferred form in the final graph. @@ -26,9 +26,10 @@ class ProvenanceTypeAttributeKind extends TypeAttributeKind> { public stringify(p: Set): string { return Array.from(p) .sort() - .map(i => i.toString()) + .map((i) => i.toString()) .join(","); } } -export const provenanceTypeAttributeKind: TypeAttributeKind> = new ProvenanceTypeAttributeKind(); +export const provenanceTypeAttributeKind: TypeAttributeKind> = + new ProvenanceTypeAttributeKind(); diff --git a/packages/quicktype-core/src/Type/TransformedStringType.ts b/packages/quicktype-core/src/Type/TransformedStringType.ts index 617ca923..6a230611 100644 --- a/packages/quicktype-core/src/Type/TransformedStringType.ts +++ b/packages/quicktype-core/src/Type/TransformedStringType.ts @@ -1,13 +1,13 @@ import { // eslint-disable-next-line @typescript-eslint/no-redeclare hasOwnProperty, - mapFromObject + mapFromObject, } from "collection-utils"; -import { type TypeAttributes } from "../attributes/TypeAttributes"; +import type { TypeAttributes } from "../attributes/TypeAttributes"; import { uriInferenceAttributesProducer } from "../attributes/URIAttributes"; -import { type Type } from "./Type"; +import type { Type } from "./Type"; /** * `jsonSchema` is the `format` to be used to represent this string type in @@ -30,39 +30,69 @@ export interface TransformedStringTypeTargets { * stringified integers map to integers. */ const transformedStringTypeTargetTypeKinds = { - "date": { jsonSchema: "date", primitive: undefined }, - "time": { jsonSchema: "time", primitive: undefined }, + date: { jsonSchema: "date", primitive: undefined }, + time: { jsonSchema: "time", primitive: undefined }, "date-time": { jsonSchema: "date-time", primitive: undefined }, - "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 + 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, }; export const transformedStringTypeTargetTypeKindsMap = mapFromObject( transformedStringTypeTargetTypeKinds as { [kind: string]: TransformedStringTypeTargets; - } + }, ); -export type TransformedStringTypeKind = keyof typeof transformedStringTypeTargetTypeKinds; +export type TransformedStringTypeKind = + keyof typeof transformedStringTypeTargetTypeKinds; export type PrimitiveStringTypeKind = "string" | TransformedStringTypeKind; -export type PrimitiveNonStringTypeKind = "none" | "any" | "null" | "bool" | "integer" | "double"; -export type PrimitiveTypeKind = PrimitiveNonStringTypeKind | PrimitiveStringTypeKind; +export type PrimitiveNonStringTypeKind = + | "none" + | "any" + | "null" + | "bool" + | "integer" + | "double"; +export type PrimitiveTypeKind = + | PrimitiveNonStringTypeKind + | PrimitiveStringTypeKind; export type NamedTypeKind = "class" | "enum" | "union"; -export type TypeKind = PrimitiveTypeKind | NamedTypeKind | "array" | "object" | "map" | "intersection"; +export type TypeKind = + | PrimitiveTypeKind + | NamedTypeKind + | "array" + | "object" + | "map" + | "intersection"; 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 { - return kind === "string" || hasOwnProperty(transformedStringTypeTargetTypeKinds, kind); +export function isPrimitiveStringTypeKind( + kind: string, +): kind is PrimitiveStringTypeKind { + return ( + kind === "string" || + hasOwnProperty(transformedStringTypeTargetTypeKinds, kind) + ); } export function targetTypeKindForTransformedStringTypeKind( - kind: PrimitiveStringTypeKind + kind: PrimitiveStringTypeKind, ): PrimitiveNonStringTypeKind | undefined { const target = transformedStringTypeTargetTypeKindsMap.get(kind); if (target === undefined) return undefined; @@ -76,7 +106,9 @@ export function isNumberTypeKind(kind: TypeKind): kind is "integer" | "double" { 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"; + return ( + kind === "none" || kind === "any" || kind === "null" || kind === "bool" + ); } export function triviallyStructurallyCompatible(x: Type, y: Type): boolean { diff --git a/packages/quicktype-core/src/Type/Type.ts b/packages/quicktype-core/src/Type/Type.ts index 37f8a5af..f7bb8372 100644 --- a/packages/quicktype-core/src/Type/Type.ts +++ b/packages/quicktype-core/src/Type/Type.ts @@ -16,12 +16,18 @@ import { setMap, setSortBy, setUnionInto, - toReadonlySet + toReadonlySet, } from "collection-utils"; -import { type TypeAttributes } from "../attributes/TypeAttributes"; -import { type TypeNames, namesTypeAttributeKind } from "../attributes/TypeNames"; -import { type BaseGraphRewriteBuilder, type TypeReconstituter } from "../GraphRewriting"; +import type { TypeAttributes } from "../attributes/TypeAttributes"; +import { + type TypeNames, + namesTypeAttributeKind, +} from "../attributes/TypeNames"; +import type { + BaseGraphRewriteBuilder, + TypeReconstituter, +} from "../GraphRewriting"; import { messageAssert } from "../Messages"; import { assert, defined, panic } from "../support/Support"; @@ -30,10 +36,15 @@ import { type PrimitiveTypeKind, type TypeKind, isPrimitiveStringTypeKind, - triviallyStructurallyCompatible + triviallyStructurallyCompatible, } from "./TransformedStringType"; -import { type TypeGraph } from "./TypeGraph"; -import { type TypeRef, attributesForTypeRef, derefTypeRef, typeRefIndex } from "./TypeRef"; +import type { TypeGraph } from "./TypeGraph"; +import { + type TypeRef, + attributesForTypeRef, + derefTypeRef, + typeRefIndex, +} from "./TypeRef"; export class TypeIdentity { private readonly _hashCode: number; @@ -41,7 +52,7 @@ export class TypeIdentity { public constructor( private readonly _kind: TypeKind, // FIXME: strongly type this - private readonly _components: readonly unknown[] + private readonly _components: readonly unknown[], ) { let h = hashCodeInit; h = addHashCode(h, hashCodeOf(this._kind)); @@ -56,9 +67,13 @@ export class TypeIdentity { if (!(other instanceof TypeIdentity)) return false; if (this._kind !== other._kind) return false; const n = this._components.length; - assert(n === other._components.length, "Components of a type kind's identity must have the same length"); + assert( + n === other._components.length, + "Components of a type kind's identity must have the same length", + ); for (let i = 0; i < n; i++) { - if (!areEqual(this._components[i], other._components[i])) return false; + if (!areEqual(this._components[i], other._components[i])) + return false; } return true; @@ -77,7 +92,7 @@ export abstract class Type { public constructor( public readonly typeRef: TypeRef, - protected readonly graph: TypeGraph + protected readonly graph: TypeGraph, ) {} public get index(): number { @@ -88,7 +103,7 @@ export abstract class Type { public abstract getNonAttributeChildren(): Set; public getChildren(): ReadonlySet { - let result = this.getNonAttributeChildren(); + const result = this.getNonAttributeChildren(); for (const [k, v] of this.getAttributes()) { if (k.children === undefined) continue; setUnionInto(result, k.children(v)); @@ -102,11 +117,16 @@ export abstract class Type { } public get hasNames(): boolean { - return namesTypeAttributeKind.tryGetInAttributes(this.getAttributes()) !== undefined; + return ( + namesTypeAttributeKind.tryGetInAttributes(this.getAttributes()) !== + undefined + ); } public getNames(): TypeNames { - return defined(namesTypeAttributeKind.tryGetInAttributes(this.getAttributes())); + return defined( + namesTypeAttributeKind.tryGetInAttributes(this.getAttributes()), + ); } public getCombinedName(): string { @@ -119,7 +139,7 @@ export abstract class Type { public abstract get identity(): MaybeTypeIdentity; public abstract reconstitute( builder: TypeReconstituter, - canonicalOrder: boolean + canonicalOrder: boolean, ): void; public get debugPrintKind(): string { @@ -140,10 +160,13 @@ export abstract class Type { protected abstract structuralEqualityStep( other: Type, conflateNumbers: boolean, - queue: (a: Type, b: Type) => boolean + queue: (a: Type, b: Type) => boolean, ): boolean; - public structurallyCompatible(other: Type, conflateNumbers = false): boolean { + public structurallyCompatible( + other: Type, + conflateNumbers = false, + ): boolean { function kindsCompatible(kind1: TypeKind, kind2: TypeKind): boolean { if (kind1 === kind2) return true; if (!conflateNumbers) return false; @@ -180,8 +203,8 @@ export abstract class Type { } if (!a.isPrimitive()) { - let ai = a.index; - let bi = b.index; + const ai = a.index; + const bi = b.index; let found = false; for (const [dai, dbi] of done) { @@ -196,7 +219,8 @@ export abstract class Type { } failed = false; - if (!a.structuralEqualityStep(b, conflateNumbers, queue)) return false; + if (!a.structuralEqualityStep(b, conflateNumbers, queue)) + return false; if (failed) return false; } @@ -242,7 +266,10 @@ 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)]); } @@ -251,13 +278,15 @@ export class PrimitiveType extends Type { public constructor( typeRef: TypeRef, graph: TypeGraph, - public readonly kind: PrimitiveTypeKind + public readonly kind: PrimitiveTypeKind, ) { super(typeRef, graph); } public get isNullable(): boolean { - return this.kind === "null" || this.kind === "any" || this.kind === "none"; + return ( + this.kind === "null" || this.kind === "any" || this.kind === "none" + ); } public isPrimitive(): this is PrimitiveType { @@ -272,22 +301,30 @@ export class PrimitiveType extends Type { return primitiveTypeIdentity(this.kind, this.getAttributes()); } - public reconstitute(builder: TypeReconstituter): void { + public reconstitute( + builder: TypeReconstituter, + ): void { builder.getPrimitiveType(this.kind); } 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]); + return new TypeIdentity("array", [ + identityAttributes(attributes), + itemsRef, + ]); } export class ArrayType extends Type { @@ -296,14 +333,14 @@ export class ArrayType extends Type { public constructor( typeRef: TypeRef, graph: TypeGraph, - private _itemsRef?: TypeRef + private _itemsRef?: TypeRef, ) { super(typeRef, graph); } public setItems(itemsRef: TypeRef): void { if (this._itemsRef !== undefined) { - return panic("Can only set array items once"); + panic("Can only set array items once"); } this._itemsRef = itemsRef; @@ -337,7 +374,9 @@ export class ArrayType extends Type { return arrayTypeIdentity(this.getAttributes(), this.getItemsRef()); } - public reconstitute(builder: TypeReconstituter): void { + public reconstitute( + builder: TypeReconstituter, + ): void { const itemsRef = this.getItemsRef(); const maybeItems = builder.lookup(itemsRef); if (maybeItems === undefined) { @@ -351,7 +390,7 @@ export class ArrayType extends Type { 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); } @@ -360,7 +399,7 @@ export class ArrayType extends Type { export class GenericClassProperty { public constructor( public readonly typeData: T, - public readonly isOptional: boolean + public readonly isOptional: boolean, ) {} public equals(other: GenericClassProperty): boolean { @@ -368,7 +407,10 @@ export class GenericClassProperty { return false; } - return areEqual(this.typeData, other.typeData) && this.isOptional === other.isOptional; + return ( + areEqual(this.typeData, other.typeData) && + this.isOptional === other.isOptional + ); } public hashCode(): number { @@ -380,7 +422,7 @@ export class ClassProperty extends GenericClassProperty { public constructor( typeRef: TypeRef, public readonly graph: TypeGraph, - isOptional: boolean + isOptional: boolean, ) { super(typeRef, isOptional); } @@ -398,24 +440,33 @@ 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]); + return new TypeIdentity(kind, [ + identityAttributes(attributes), + properties, + additionalPropertiesRef, + ]); } export function classTypeIdentity( attributes: TypeAttributes, - properties: ReadonlyMap + properties: ReadonlyMap, ): MaybeTypeIdentity { return objectTypeIdentify("class", attributes, properties, undefined); } export function mapTypeIdentify( attributes: TypeAttributes, - additionalPropertiesRef: TypeRef | undefined + additionalPropertiesRef: TypeRef | undefined, ): MaybeTypeIdentity { - return objectTypeIdentify("map", attributes, new Map(), additionalPropertiesRef); + return objectTypeIdentify( + "map", + attributes, + new Map(), + additionalPropertiesRef, + ); } export class ObjectType extends Type { @@ -425,7 +476,7 @@ export class ObjectType extends Type { public readonly kind: ObjectTypeKind, public readonly isFixed: boolean, private _properties: ReadonlyMap | undefined, - private _additionalPropertiesRef: TypeRef | undefined + private _additionalPropertiesRef: TypeRef | undefined, ) { super(typeRef, graph); @@ -444,16 +495,22 @@ export class ObjectType extends Type { public setProperties( properties: ReadonlyMap, - additionalPropertiesRef: TypeRef | undefined + additionalPropertiesRef: TypeRef | undefined, ): void { - assert(this._properties === undefined, "Tried to set object properties twice"); + assert( + this._properties === undefined, + "Tried to set object properties twice", + ); if (this instanceof MapType) { assert(properties.size === 0, "Cannot set properties on map type"); } if (this instanceof ClassType) { - assert(additionalPropertiesRef === undefined, "Cannot set additional properties of class type"); + assert( + additionalPropertiesRef === undefined, + "Cannot set additional properties of class type", + ); } this._properties = properties; @@ -480,7 +537,9 @@ export class ObjectType extends Type { } public getNonAttributeChildren(): Set { - const types = mapSortToArray(this.getProperties(), (_, k) => k).map(([_, p]) => p.type); + const types = mapSortToArray(this.getProperties(), (_, k) => k).map( + ([_, p]) => p.type, + ); const additionalProperties = this.getAdditionalProperties(); if (additionalProperties !== undefined) { types.push(additionalProperties); @@ -503,31 +562,45 @@ export class ObjectType extends Type { this.kind, this.getAttributes(), this.getProperties(), - this.getAdditionalPropertiesRef() + this.getAdditionalPropertiesRef(), ); } public reconstitute( builder: TypeReconstituter, - canonicalOrder: boolean + canonicalOrder: boolean, ): void { const sortedProperties = this.getSortedProperties(); - const propertiesInNewOrder = canonicalOrder ? sortedProperties : this.getProperties(); - const maybePropertyTypes = builder.lookupMap(mapMap(sortedProperties, cp => cp.typeRef)); - const maybeAdditionalProperties = definedMap(this._additionalPropertiesRef, r => builder.lookup(r)); + const propertiesInNewOrder = canonicalOrder + ? sortedProperties + : this.getProperties(); + const maybePropertyTypes = builder.lookupMap( + mapMap(sortedProperties, (cp) => cp.typeRef), + ); + const maybeAdditionalProperties = definedMap( + this._additionalPropertiesRef, + (r) => builder.lookup(r), + ); if ( maybePropertyTypes !== undefined && - (maybeAdditionalProperties !== undefined || this._additionalPropertiesRef === undefined) + (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) { case "object": assert(this.isFixed); - builder.getObjectType(properties, maybeAdditionalProperties); + builder.getObjectType( + properties, + maybeAdditionalProperties, + ); break; case "map": builder.getMapType(defined(maybeAdditionalProperties)); @@ -541,7 +614,7 @@ export class ObjectType extends Type { break; default: - return panic(`Invalid object type kind ${this.kind}`); + panic(`Invalid object type kind ${this.kind}`); } } else { switch (this.kind) { @@ -556,14 +629,22 @@ export class ObjectType extends Type { builder.getUniqueClassType(this.isFixed, undefined); break; default: - return panic(`Invalid object type kind ${this.kind}`); + panic(`Invalid object type kind ${this.kind}`); } - const reconstitutedTypes = mapMap(sortedProperties, cp => builder.reconstitute(cp.typeRef)); - const properties = mapMap(propertiesInNewOrder, (cp, n) => - builder.makeClassProperty(defined(reconstitutedTypes.get(n)), cp.isOptional) + const reconstitutedTypes = mapMap(sortedProperties, (cp) => + builder.reconstitute(cp.typeRef), + ); + const properties = mapMap(propertiesInNewOrder, (cp, n) => + builder.makeClassProperty( + defined(reconstitutedTypes.get(n)), + cp.isOptional, + ), + ); + const additionalProperties = definedMap( + this._additionalPropertiesRef, + (r) => builder.reconstitute(r), ); - const additionalProperties = definedMap(this._additionalPropertiesRef, r => builder.reconstitute(r)); builder.setObjectProperties(properties, additionalProperties); } } @@ -571,7 +652,7 @@ export class ObjectType extends Type { 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(); @@ -579,7 +660,11 @@ export class ObjectType extends Type { let failed = false; for (const [name, cpa] of pa) { const cpb = pb.get(name); - if (cpb === undefined || cpa.isOptional !== cpb.isOptional || !queue(cpa.type, cpb.type)) { + if ( + cpb === undefined || + cpa.isOptional !== cpb.isOptional || + !queue(cpa.type, cpb.type) + ) { failed = true; return false; } @@ -589,8 +674,16 @@ 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 true; + if ( + (thisAdditionalProperties === undefined) !== + (otherAdditionalProperties === undefined) + ) + return false; + if ( + thisAdditionalProperties === undefined || + otherAdditionalProperties === undefined + ) + return true; return queue(thisAdditionalProperties, otherAdditionalProperties); } } @@ -600,21 +693,25 @@ export class ClassType extends ObjectType { typeRef: TypeRef, graph: TypeGraph, isFixed: boolean, - properties: ReadonlyMap | undefined + properties: ReadonlyMap | undefined, ) { super(typeRef, graph, "class", isFixed, properties, undefined); } } export class MapType extends ObjectType { - public 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, ); } @@ -624,7 +721,10 @@ export class MapType extends ObjectType { } } -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]); } @@ -635,7 +735,7 @@ export class EnumType extends Type { public constructor( typeRef: TypeRef, graph: TypeGraph, - public readonly cases: ReadonlySet + public readonly cases: ReadonlySet, ) { super(typeRef, graph); } @@ -656,14 +756,16 @@ export class EnumType extends Type { return new Set(); } - public reconstitute(builder: TypeReconstituter): void { + public reconstitute( + builder: TypeReconstituter, + ): void { builder.getEnumType(this.cases); } 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); } @@ -673,20 +775,28 @@ 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); if (ma.size !== mb.size) return false; - return iterableEvery(ma, ta => { - const tb = iterableFind(mb, t => t.kind === ta.kind); + return iterableEvery(ma, (ta) => { + const tb = iterableFind(mb, (t) => t.kind === ta.kind); 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; + 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; @@ -696,19 +806,22 @@ export function setOperationCasesEqual( 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( attributes: TypeAttributes, - memberRefs: ReadonlySet + memberRefs: ReadonlySet, ): MaybeTypeIdentity { return setOperationTypeIdentity("intersection", attributes, memberRefs); } @@ -718,14 +831,14 @@ export abstract class SetOperationType extends Type { typeRef: TypeRef, graph: TypeGraph, public readonly kind: TypeKind, - private _memberRefs?: ReadonlySet + private _memberRefs?: ReadonlySet, ) { super(typeRef, graph); } public setMembers(memberRefs: ReadonlySet): void { if (this._memberRefs !== undefined) { - return panic("Can only set map members once"); + panic("Can only set map members once"); } this._memberRefs = memberRefs; @@ -740,7 +853,9 @@ export abstract class SetOperationType extends Type { } public get members(): ReadonlySet { - return setMap(this.getMemberRefs(), tref => derefTypeRef(tref, this.graph)); + return setMap(this.getMemberRefs(), (tref) => + derefTypeRef(tref, this.graph), + ); } public get sortedMembers(): ReadonlySet { @@ -749,7 +864,7 @@ export abstract class SetOperationType extends Type { public getNonAttributeChildren(): Set { // FIXME: We're assuming no two members of the same kind. - return setSortBy(this.members, t => t.kind); + return setSortBy(this.members, (t) => t.kind); } public isPrimitive(): this is PrimitiveType { @@ -757,37 +872,59 @@ export abstract class SetOperationType extends Type { } public get identity(): MaybeTypeIdentity { - return setOperationTypeIdentity(this.kind, this.getAttributes(), this.getMemberRefs()); + 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; + const sortedMemberRefs = mapMap( + this.sortedMembers.entries(), + (t) => t.typeRef, + ); + const membersInOrder = canonicalOrder + ? this.sortedMembers + : this.members; const maybeMembers = builder.lookupMap(sortedMemberRefs); if (maybeMembers === undefined) { getType(undefined); const reconstituted = builder.reconstituteMap(sortedMemberRefs); - builder.setSetOperationMembers(setMap(membersInOrder, t => defined(reconstituted.get(t)))); + builder.setSetOperationMembers( + setMap(membersInOrder, (t) => defined(reconstituted.get(t))), + ); } else { - getType(setMap(membersInOrder, t => defined(maybeMembers.get(t)))); + getType( + setMap(membersInOrder, (t) => defined(maybeMembers.get(t))), + ); } } 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); + return setOperationCasesEqual( + this.members, + other.members, + conflateNumbers, + queue, + ); } } export class IntersectionType extends SetOperationType { - public constructor(typeRef: TypeRef, graph: TypeGraph, memberRefs?: ReadonlySet) { + public constructor( + typeRef: TypeRef, + graph: TypeGraph, + memberRefs?: ReadonlySet, + ) { super(typeRef, graph, "intersection", memberRefs); } @@ -797,9 +934,9 @@ export class IntersectionType extends SetOperationType { public reconstitute( builder: TypeReconstituter, - canonicalOrder: boolean + canonicalOrder: boolean, ): void { - this.reconstituteSetOperation(builder, canonicalOrder, members => { + this.reconstituteSetOperation(builder, canonicalOrder, (members) => { if (members === undefined) { builder.getUniqueIntersectionType(); } else { @@ -810,7 +947,11 @@ export class IntersectionType extends SetOperationType { } export class UnionType extends SetOperationType { - public 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", {}); @@ -823,11 +964,14 @@ export class UnionType extends SetOperationType { } public get stringTypeMembers(): ReadonlySet { - return setFilter(this.members, t => isPrimitiveStringTypeKind(t.kind) || t.kind === "enum"); + return setFilter( + this.members, + (t) => isPrimitiveStringTypeKind(t.kind) || t.kind === "enum", + ); } public findMember(kind: TypeKind): Type | undefined { - return iterableFind(this.members, t => t.kind === kind); + return iterableFind(this.members, (t) => t.kind === kind); } public get isNullable(): boolean { @@ -837,7 +981,7 @@ export class UnionType extends SetOperationType { public get isCanonical(): boolean { const members = this.members; if (members.size <= 1) return false; - const kinds = setMap(members, t => t.kind); + const kinds = setMap(members, (t) => t.kind); if (kinds.size < members.size) return false; if (kinds.has("union") || kinds.has("intersection")) return false; if (kinds.has("none") || kinds.has("any")) return false; @@ -854,9 +998,9 @@ export class UnionType extends SetOperationType { public reconstitute( builder: TypeReconstituter, - canonicalOrder: boolean + canonicalOrder: boolean, ): void { - this.reconstituteSetOperation(builder, canonicalOrder, members => { + this.reconstituteSetOperation(builder, canonicalOrder, (members) => { if (members === undefined) { builder.getUniqueUnionType(); } else { diff --git a/packages/quicktype-core/src/Type/TypeBuilder.ts b/packages/quicktype-core/src/Type/TypeBuilder.ts index d732312d..9f04812d 100644 --- a/packages/quicktype-core/src/Type/TypeBuilder.ts +++ b/packages/quicktype-core/src/Type/TypeBuilder.ts @@ -7,15 +7,25 @@ import { mapFind, mapMap, mapSortByKey, - withDefault + withDefault, } from "collection-utils"; -import { StringTypes, stringTypesTypeAttributeKind } from "../attributes/StringTypes"; -import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "../attributes/TypeAttributes"; +import { + StringTypes, + stringTypesTypeAttributeKind, +} from "../attributes/StringTypes"; +import { + type TypeAttributes, + combineTypeAttributes, + emptyTypeAttributes, +} from "../attributes/TypeAttributes"; import { assert, defined, panic } from "../support/Support"; import { provenanceTypeAttributeKind } from "./ProvenanceTypeAttributeKind"; -import { type PrimitiveTypeKind, isPrimitiveStringTypeKind } from "./TransformedStringType"; +import { + type PrimitiveTypeKind, + isPrimitiveStringTypeKind, +} from "./TransformedStringType"; import { ArrayType, ClassProperty, @@ -35,11 +45,20 @@ import { intersectionTypeIdentity, mapTypeIdentify, primitiveTypeIdentity, - unionTypeIdentity + unionTypeIdentity, } from "./Type"; -import { type StringTypeMapping, stringTypeMappingGet } from "./TypeBuilderUtils"; -import { type TypeGraph } from "./TypeGraph"; -import { type TypeRef, assertTypeRefGraph, derefTypeRef, makeTypeRef, typeRefIndex } from "./TypeRef"; +import { + type StringTypeMapping, + stringTypeMappingGet, +} from "./TypeBuilderUtils"; +import type { TypeGraph } from "./TypeGraph"; +import { + type TypeRef, + assertTypeRefGraph, + derefTypeRef, + makeTypeRef, + typeRefIndex, +} from "./TypeRef"; export class TypeBuilder { // @ts-expect-error must manually set TypeGraph @@ -58,11 +77,11 @@ export class TypeBuilder { 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", ); } @@ -71,17 +90,20 @@ export class TypeBuilder { return this._typeGraph; } - /** typeGraph must be set externally to prevent import cycle of TypeGraph constructor */ + /** typeGraph must be set externally to prevent import cycle of TypeGraph constructor */ public set typeGraph(typeGraph: TypeGraph) { this._typeGraph = typeGraph; } 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.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); } @@ -103,13 +125,20 @@ export class TypeBuilder { 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)); + trefs.forEach((tref) => this.assertTypeRefGraph(tref)); } - private filterTypeAttributes(t: Type, attributes: TypeAttributes): TypeAttributes { - const filtered = mapFilter(attributes, (_, k) => k.appliesToTypeKind(t.kind)); + private filterTypeAttributes( + t: Type, + attributes: TypeAttributes, + ): TypeAttributes { + const filtered = mapFilter(attributes, (_, k) => + k.appliesToTypeKind(t.kind), + ); if (attributes.size !== filtered.size) { this.setLostTypeAttributes(); } @@ -122,15 +151,21 @@ export class TypeBuilder { const index = typeRefIndex(tref); // const name = names !== undefined ? ` ${names.combinedName}` : ""; // console.log(`committing ${t.kind}${name} to ${index}`); - assert(this.types[index] === undefined, "A type index was committed twice"); + assert( + this.types[index] === undefined, + "A type index was committed twice", + ); this.types[index] = t; - this.typeAttributes[index] = this.filterTypeAttributes(t, this.typeAttributes[index]); + this.typeAttributes[index] = this.filterTypeAttributes( + t, + this.typeAttributes[index], + ); } protected addType( forwardingRef: TypeRef | undefined, creator: (tref: TypeRef) => T, - attributes: TypeAttributes | undefined + attributes: TypeAttributes | undefined, ): TypeRef { if (forwardingRef !== undefined) { this.assertTypeRefGraph(forwardingRef); @@ -140,7 +175,11 @@ export class TypeBuilder { const tref = forwardingRef ?? this.reserveTypeRef(); if (attributes !== undefined) { const index = typeRefIndex(tref); - this.typeAttributes[index] = combineTypeAttributes("union", this.typeAttributes[index], attributes); + this.typeAttributes[index] = combineTypeAttributes( + "union", + this.typeAttributes[index], + attributes, + ); } const t = creator(tref); @@ -174,32 +213,62 @@ 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); + const nonIdentityAttributes = mapFilter( + attributes, + (_, k) => !k.inIdentity, + ); + this.typeAttributes[index] = combineTypeAttributes( + "union", + existingAttributes, + nonIdentityAttributes, + ); } public finish(): TypeGraph { - this.typeGraph.freeze(this.topLevels, this.types.map(defined), this.typeAttributes); + 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); + 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); @@ -209,9 +278,13 @@ export class TypeBuilder { return this._addedForwardingIntersection; } - private readonly _typeForIdentity: EqualityMap = new EqualityMap(); + 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); } @@ -224,7 +297,7 @@ export class TypeBuilder { 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; @@ -243,7 +316,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), ); } @@ -262,12 +335,13 @@ export class TypeBuilder { public getPrimitiveType( kind: PrimitiveTypeKind, maybeAttributes?: TypeAttributes, - forwardingRef?: TypeRef + 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 - let stringTypes = kind === "string" ? undefined : StringTypes.unrestricted; + const stringTypes = + kind === "string" ? undefined : StringTypes.unrestricted; if (isPrimitiveStringTypeKind(kind) && kind !== "string") { kind = stringTypeMappingGet(this._stringTypeMapping, kind); } @@ -278,48 +352,60 @@ export class TypeBuilder { return this.getOrAddType( () => primitiveTypeIdentity(kind, attributes), - tr => new PrimitiveType(tr, this.typeGraph, kind), + (tr) => new PrimitiveType(tr, this.typeGraph, kind), attributes, - forwardingRef + forwardingRef, ); } public getStringType( attributes: TypeAttributes, stringTypes: StringTypes | undefined, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { - const existingStringTypes = mapFind(attributes, (_, k) => k === stringTypesTypeAttributeKind); + const existingStringTypes = mapFind( + attributes, + (_, k) => k === stringTypesTypeAttributeKind, + ); assert( (stringTypes === undefined) !== (existingStringTypes === undefined), - "Must instantiate string type with one enum case attribute" + "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"), + (tr) => new PrimitiveType(tr, this.typeGraph, "string"), attributes, - forwardingRef + forwardingRef, ); } - public 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), + (tr) => new EnumType(tr, this.typeGraph, cases), attributes, - forwardingRef + forwardingRef, ); } - public makeClassProperty(tref: TypeRef, isOptional: boolean): ClassProperty { + public makeClassProperty( + tref: TypeRef, + isOptional: boolean, + ): ClassProperty { return new ClassProperty(tref, this.typeGraph, isOptional); } @@ -327,37 +413,55 @@ export class TypeBuilder { attributes: TypeAttributes, properties: ReadonlyMap | undefined, additionalProperties: TypeRef | undefined, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { this.assertTypeRefGraph(additionalProperties); - properties = definedMap(properties, p => this.modifyPropertiesIfNecessary(p)); + properties = definedMap(properties, (p) => + this.modifyPropertiesIfNecessary(p), + ); return this.addType( forwardingRef, - tref => new ObjectType(tref, this.typeGraph, "object", true, properties, additionalProperties), - attributes + (tref) => + new ObjectType( + tref, + this.typeGraph, + "object", + true, + properties, + additionalProperties, + ), + attributes, ); } public getUniqueMapType(forwardingRef?: TypeRef): TypeRef { - return this.addType(forwardingRef, tr => new MapType(tr, this.typeGraph, undefined), undefined); + return this.addType( + forwardingRef, + (tr) => new MapType(tr, this.typeGraph, undefined), + undefined, + ); } - public 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), + (tr) => new MapType(tr, this.typeGraph, values), attributes, - forwardingRef + forwardingRef, ); } public setObjectProperties( ref: TypeRef, properties: ReadonlyMap, - additionalProperties: TypeRef | undefined + additionalProperties: TypeRef | undefined, ): void { this.assertTypeRefGraph(additionalProperties); @@ -366,22 +470,33 @@ export class TypeBuilder { return panic("Tried to set properties of non-object type"); } - type.setProperties(this.modifyPropertiesIfNecessary(properties), additionalProperties); + type.setProperties( + this.modifyPropertiesIfNecessary(properties), + additionalProperties, + ); this.registerType(type); } public getUniqueArrayType(forwardingRef?: TypeRef): TypeRef { - return this.addType(forwardingRef, tr => new ArrayType(tr, this.typeGraph, undefined), undefined); + return this.addType( + forwardingRef, + (tr) => new ArrayType(tr, this.typeGraph, undefined), + undefined, + ); } - public 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), + (tr) => new ArrayType(tr, this.typeGraph, items), attributes, - forwardingRef + forwardingRef, ); } @@ -390,7 +505,7 @@ export class TypeBuilder { const type = derefTypeRef(ref, this.typeGraph); if (!(type instanceof ArrayType)) { - return panic("Tried to set items of non-array type"); + panic("Tried to set items of non-array type"); } type.setItems(items); @@ -398,16 +513,18 @@ export class TypeBuilder { } public modifyPropertiesIfNecessary( - properties: ReadonlyMap + properties: ReadonlyMap, ): ReadonlyMap { - properties.forEach(p => this.assertTypeRefGraph(p.typeRef)); + 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)); + properties = mapMap(properties, (cp) => + this.makeClassProperty(cp.typeRef, true), + ); } return properties; @@ -416,14 +533,14 @@ export class TypeBuilder { 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), + (tr) => new ClassType(tr, this.typeGraph, false, properties), attributes, - forwardingRef + forwardingRef, ); } @@ -433,24 +550,30 @@ export class TypeBuilder { attributes: TypeAttributes, isFixed: boolean, properties: ReadonlyMap | undefined, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { - properties = definedMap(properties, p => this.modifyPropertiesIfNecessary(p)); + properties = definedMap(properties, (p) => + this.modifyPropertiesIfNecessary(p), + ); return this.addType( forwardingRef, - tref => new ClassType(tref, this.typeGraph, isFixed, properties), - attributes + (tref) => new ClassType(tref, this.typeGraph, isFixed, properties), + attributes, ); } - public 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), + (tr) => new UnionType(tr, this.typeGraph, members), attributes, - forwardingRef + forwardingRef, ); } @@ -458,25 +581,29 @@ export class TypeBuilder { 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); + return this.addType( + forwardingRef, + (tref) => new UnionType(tref, this.typeGraph, members), + attributes, + ); } public getIntersectionType( attributes: TypeAttributes, members: ReadonlySet, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { this.assertTypeRefSetGraph(members); return this.getOrAddType( () => intersectionTypeIdentity(attributes, members), - tr => new IntersectionType(tr, this.typeGraph, members), + (tr) => new IntersectionType(tr, this.typeGraph, members), attributes, - forwardingRef + forwardingRef, ); } @@ -484,19 +611,26 @@ export class TypeBuilder { 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); + return this.addType( + forwardingRef, + (tref) => new IntersectionType(tref, this.typeGraph, members), + attributes, + ); } - public setSetOperationMembers(ref: TypeRef, members: ReadonlySet): void { + public 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"); + panic("Tried to set members of non-set-operation type"); } type.setMembers(members); diff --git a/packages/quicktype-core/src/Type/TypeBuilderUtils.ts b/packages/quicktype-core/src/Type/TypeBuilderUtils.ts index f2006fad..7743f361 100644 --- a/packages/quicktype-core/src/Type/TypeBuilderUtils.ts +++ b/packages/quicktype-core/src/Type/TypeBuilderUtils.ts @@ -1,12 +1,18 @@ import { type PrimitiveStringTypeKind, type TransformedStringTypeKind, - transformedStringTypeKinds + transformedStringTypeKinds, } from "./TransformedStringType"; -export type StringTypeMapping = ReadonlyMap; +export type StringTypeMapping = ReadonlyMap< + TransformedStringTypeKind, + PrimitiveStringTypeKind +>; -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; @@ -18,8 +24,12 @@ 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, + ], + ), ); } diff --git a/packages/quicktype-core/src/Type/TypeGraph.ts b/packages/quicktype-core/src/Type/TypeGraph.ts index 7d34591f..f20f3a20 100644 --- a/packages/quicktype-core/src/Type/TypeGraph.ts +++ b/packages/quicktype-core/src/Type/TypeGraph.ts @@ -1,25 +1,45 @@ import { mapMap, setSubtract, setUnionManyInto } from "collection-utils"; -import { type TypeAttributeKind, type TypeAttributes, emptyTypeAttributes } from "../attributes/TypeAttributes"; +import { + type TypeAttributeKind, + type TypeAttributes, + emptyTypeAttributes, +} from "../attributes/TypeAttributes"; import { Graph } from "../Graph"; -import { type BaseGraphRewriteBuilder, GraphRemapBuilder, GraphRewriteBuilder } from "../GraphRewriting"; +import { + type BaseGraphRewriteBuilder, + GraphRemapBuilder, + GraphRewriteBuilder, +} from "../GraphRewriting"; import { messageError } from "../Messages"; import { assert, defined, mustNotHappen } from "../support/Support"; import { provenanceTypeAttributeKind } from "./ProvenanceTypeAttributeKind"; -import { type Type } from "./Type"; -import { type TypeBuilder } from "./TypeBuilder"; -import { type StringTypeMapping, getNoStringTypeMapping } from "./TypeBuilderUtils"; +import type { Type } from "./Type"; +import type { TypeBuilder } from "./TypeBuilder"; +import { + type StringTypeMapping, + getNoStringTypeMapping, +} from "./TypeBuilderUtils"; import { removeIndirectionIntersections } from "./TypeGraphUtils"; -import { type TypeRef, assertTypeRefGraph, derefTypeRef, typeRefIndex } from "./TypeRef"; -import { type SeparatedNamedTypes, isNamedType, separateNamedTypes } from "./TypeUtils"; +import { + type TypeRef, + assertTypeRefGraph, + derefTypeRef, + typeRefIndex, +} from "./TypeRef"; +import { + type SeparatedNamedTypes, + isNamedType, + separateNamedTypes, +} from "./TypeUtils"; export class TypeAttributeStore { private readonly _topLevelValues: Map = new Map(); public constructor( private readonly _typeGraph: TypeGraph, - private _values: Array + private _values: Array, ) {} private getTypeIndex(t: Type): number { @@ -47,7 +67,11 @@ export class TypeAttributeStore { return emptyTypeAttributes; } - public 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); } @@ -58,14 +82,32 @@ export class TypeAttributeStore { this._values.push(undefined); } - this._values[index] = this.setInMap(this.attributesForType(t), kind, value); + this._values[index] = this.setInMap( + this.attributesForType(t), + kind, + value, + ); } - public setForTopLevel(kind: TypeAttributeKind, topLevelName: string, value: T): void { - this._topLevelValues.set(topLevelName, this.setInMap(this.attributesForTopLevel(topLevelName), kind, value)); + public setForTopLevel( + kind: TypeAttributeKind, + topLevelName: string, + value: T, + ): void { + this._topLevelValues.set( + topLevelName, + this.setInMap( + this.attributesForTopLevel(topLevelName), + kind, + value, + ), + ); } - public tryGetInMap(attributes: TypeAttributes, kind: TypeAttributeKind): T | undefined { + public tryGetInMap( + attributes: TypeAttributes, + kind: TypeAttributeKind, + ): T | undefined { return attributes.get(kind); } @@ -73,7 +115,10 @@ export class TypeAttributeStore { return this.tryGetInMap(this.attributesForType(t), kind); } - public tryGetForTopLevel(kind: TypeAttributeKind, topLevelName: string): T | undefined { + public tryGetForTopLevel( + kind: TypeAttributeKind, + topLevelName: string, + ): T | undefined { return this.tryGetInMap(this.attributesForTopLevel(topLevelName), kind); } } @@ -81,7 +126,7 @@ export class TypeAttributeStore { export class TypeAttributeStoreView { public constructor( private readonly _attributeStore: TypeAttributeStore, - private readonly _definition: TypeAttributeKind + private readonly _definition: TypeAttributeKind, ) {} public set(t: Type, value: T): void { @@ -127,7 +172,7 @@ export class TypeGraph { public constructor( typeBuilder: TypeBuilder, public readonly serial: number, - private readonly _haveProvenanceAttributes: boolean + private readonly _haveProvenanceAttributes: boolean, ) { this._typeBuilder = typeBuilder; } @@ -143,7 +188,7 @@ export class TypeGraph { 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) { @@ -158,7 +203,7 @@ export class TypeGraph { // either a _typeBuilder or a _types. this._types = types; this._typeBuilder = undefined; - this._topLevels = mapMap(topLevels, tref => derefTypeRef(tref, this)); + this._topLevels = mapMap(topLevels, (tref) => derefTypeRef(tref, this)); } public get topLevels(): ReadonlyMap { @@ -185,9 +230,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[] = []; + const types: Type[] = []; function addFromType(t: Type): void { if (seen.has(t)) { @@ -227,8 +274,11 @@ export class TypeGraph { private allProvenance(): ReadonlySet { assert(this._haveProvenanceAttributes); - const view = new TypeAttributeStoreView(this.attributeStore, provenanceTypeAttributeKind); - const sets = Array.from(this.allTypesUnordered()).map(t => { + const view = new TypeAttributeStoreView( + this.attributeStore, + provenanceTypeAttributeKind, + ); + const sets = Array.from(this.allTypesUnordered()).map((t) => { const maybeSet = view.tryGet(t); if (maybeSet !== undefined) return maybeSet; return new Set(); @@ -243,7 +293,10 @@ export class TypeGraph { this._printOnRewrite = true; } - private checkLostTypeAttributes(builder: BaseGraphRewriteBuilder, newGraph: TypeGraph): void { + private checkLostTypeAttributes( + builder: BaseGraphRewriteBuilder, + newGraph: TypeGraph, + ): void { if (!this._haveProvenanceAttributes || builder.lostTypeAttributes) { return; } @@ -253,7 +306,10 @@ export class TypeGraph { if (oldProvenance.size !== newProvenance.size) { const difference = setSubtract(oldProvenance, newProvenance); const indexes = Array.from(difference); - return messageError("IRTypeAttributesNotPropagated", { count: difference.size, indexes }); + messageError("IRTypeAttributesNotPropagated", { + count: difference.size, + indexes, + }); } } @@ -277,8 +333,12 @@ export class TypeGraph { alphabetizeProperties: boolean, replacementGroups: T[][], debugPrintReconstitution: boolean, - replacer: (typesToReplace: ReadonlySet, builder: GraphRewriteBuilder, forwardingRef: TypeRef) => TypeRef, - force = false + replacer: ( + typesToReplace: ReadonlySet, + builder: GraphRewriteBuilder, + forwardingRef: TypeRef, + ) => TypeRef, + force = false, ): TypeGraph { this.printRewrite(title); @@ -293,9 +353,13 @@ export class TypeGraph { this._haveProvenanceAttributes, replacementGroups, debugPrintReconstitution, - replacer + replacer, + ); + builder.typeGraph = new TypeGraph( + builder, + this.serial + 1, + this._haveProvenanceAttributes, ); - builder.typeGraph = new TypeGraph(builder, this.serial + 1, this._haveProvenanceAttributes); const newGraph = builder.finish(); this.checkLostTypeAttributes(builder, newGraph); @@ -309,7 +373,11 @@ export class TypeGraph { return newGraph; } - return removeIndirectionIntersections(newGraph, stringTypeMapping, debugPrintReconstitution); + return removeIndirectionIntersections( + newGraph, + stringTypeMapping, + debugPrintReconstitution, + ); } public remap( @@ -318,7 +386,7 @@ export class TypeGraph { alphabetizeProperties: boolean, map: ReadonlyMap, debugPrintRemapping: boolean, - force = false + force = false, ): TypeGraph { this.printRewrite(title); @@ -332,9 +400,13 @@ export class TypeGraph { alphabetizeProperties, this._haveProvenanceAttributes, map, - debugPrintRemapping + debugPrintRemapping, + ); + builder.typeGraph = new TypeGraph( + builder, + this.serial + 1, + this._haveProvenanceAttributes, ); - builder.typeGraph = new TypeGraph(builder, this.serial + 1, this._haveProvenanceAttributes); const newGraph = builder.finish(); this.checkLostTypeAttributes(builder, newGraph); @@ -349,20 +421,26 @@ export class TypeGraph { return newGraph; } - public 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; } - public rewriteFixedPoint(alphabetizeProperties: boolean, debugPrintReconstitution: boolean): TypeGraph { + public rewriteFixedPoint( + alphabetizeProperties: boolean, + debugPrintReconstitution: boolean, + ): TypeGraph { // eslint-disable-next-line @typescript-eslint/no-this-alias let graph: TypeGraph = this; for (;;) { @@ -373,9 +451,12 @@ export class TypeGraph { [], debugPrintReconstitution, mustNotHappen, - true + true, ); - if (graph.allTypesUnordered().size === newGraph.allTypesUnordered().size) { + if ( + graph.allTypesUnordered().size === + newGraph.allTypesUnordered().size + ) { return graph; } @@ -384,18 +465,24 @@ export class TypeGraph { } public allTypesUnordered(): ReadonlySet { - assert(this.isFrozen, "Tried to get all graph types before it was frozen"); + assert( + this.isFrozen, + "Tried to get all graph types before it was frozen", + ); return new Set(defined(this._types)); } - public 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); } public getParentsOfType(t: Type): Set { assertTypeRefGraph(t.typeRef, this); if (this._parents === undefined) { - const parents = defined(this._types).map(_ => new Set()); + const parents = defined(this._types).map((_) => new Set()); for (const p of this.allTypesUnordered()) { for (const c of p.getChildren()) { const index = c.index; @@ -414,13 +501,15 @@ export class TypeGraph { for (let i = 0; i < types.length; i++) { const t = types[i]; const parts: string[] = []; - parts.push(`${t.debugPrintKind}${t.hasNames ? ` ${t.getCombinedName()}` : ""}`); + parts.push( + `${t.debugPrintKind}${t.hasNames ? ` ${t.getCombinedName()}` : ""}`, + ); const children = t.getChildren(); if (children.size > 0) { parts.push( `children ${Array.from(children) - .map(c => c.index) - .join(",")}` + .map((c) => c.index) + .join(",")}`, ); } diff --git a/packages/quicktype-core/src/Type/TypeGraphUtils.ts b/packages/quicktype-core/src/Type/TypeGraphUtils.ts index af163435..cecc04fb 100644 --- a/packages/quicktype-core/src/Type/TypeGraphUtils.ts +++ b/packages/quicktype-core/src/Type/TypeGraphUtils.ts @@ -1,21 +1,30 @@ -import { iterableFirst, mapMap, mapSome, setFilter, setMap } from "collection-utils"; +import { + iterableFirst, + mapMap, + mapSome, + setFilter, + setMap, +} from "collection-utils"; import { TypeNames, namesTypeAttributeKind } from "../attributes/TypeNames"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; +import type { GraphRewriteBuilder } from "../GraphRewriting"; import { assert, defined, panic } from "../support/Support"; import { ClassType, IntersectionType, type Type, UnionType } from "./Type"; -import { type StringTypeMapping } from "./TypeBuilderUtils"; -import { type TypeGraph } from "./TypeGraph"; -import { type TypeRef } from "./TypeRef"; +import type { StringTypeMapping } from "./TypeBuilderUtils"; +import type { TypeGraph } from "./TypeGraph"; +import type { TypeRef } from "./TypeRef"; import { combineTypeAttributesOfTypes } from "./TypeUtils"; export function noneToAny( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { - const noneTypes = setFilter(graph.allTypesUnordered(), t => t.kind === "none"); + const noneTypes = setFilter( + graph.allTypesUnordered(), + (t) => t.kind === "none", + ); if (noneTypes.size === 0) { return graph; } @@ -29,18 +38,26 @@ export function noneToAny( debugPrintReconstitution, (types, builder, forwardingRef) => { const attributes = combineTypeAttributesOfTypes("union", types); - const tref = builder.getPrimitiveType("any", attributes, forwardingRef); + const tref = builder.getPrimitiveType( + "any", + attributes, + forwardingRef, + ); return tref; - } + }, ); } 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; @@ -50,31 +67,48 @@ export function optionalToNullable( const nullType = builder.getPrimitiveType("null"); let members: ReadonlySet; if (t instanceof UnionType) { - members = setMap(t.members, m => builder.reconstituteType(m)).add(nullType); + members = setMap(t.members, (m) => + builder.reconstituteType(m), + ).add(nullType); } else { members = new Set([builder.reconstituteType(t), nullType]); } - const attributes = namesTypeAttributeKind.setDefaultInAttributes(t.getAttributes(), () => - TypeNames.make(new Set([name]), new Set(), true) - ); + const attributes = + namesTypeAttributeKind.setDefaultInAttributes( + t.getAttributes(), + () => TypeNames.make(new Set([name]), new Set(), true), + ); ref = builder.getUnionType(attributes, members); } return builder.makeClassProperty(ref, p.isOptional); }); if (c.isFixed) { - return builder.getUniqueClassType(c.getAttributes(), true, properties, forwardingRef); + return builder.getUniqueClassType( + c.getAttributes(), + true, + properties, + forwardingRef, + ); } else { - return builder.getClassType(c.getAttributes(), properties, forwardingRef); + return builder.getClassType( + c.getAttributes(), + properties, + forwardingRef, + ); } } 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]); + const replacementGroups = Array.from(classesWithOptional).map((c) => [ + c as ClassType, + ]); if (classesWithOptional.size === 0) { return graph; } @@ -89,14 +123,14 @@ export function optionalToNullable( assert(setOfClass.size === 1); const c = defined(iterableFirst(setOfClass)); return rewriteClass(c, builder, forwardingRef); - } + }, ); } export function removeIndirectionIntersections( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintRemapping: boolean + debugPrintRemapping: boolean, ): TypeGraph { const map: Array<[Type, Type]> = []; @@ -121,5 +155,11 @@ export function removeIndirectionIntersections( } } - return graph.remap("remove indirection intersections", stringTypeMapping, false, new Map(map), debugPrintRemapping); + return graph.remap( + "remove indirection intersections", + stringTypeMapping, + false, + new Map(map), + debugPrintRemapping, + ); } diff --git a/packages/quicktype-core/src/Type/TypeRef.ts b/packages/quicktype-core/src/Type/TypeRef.ts index 4e8c3e58..c7afd16e 100644 --- a/packages/quicktype-core/src/Type/TypeRef.ts +++ b/packages/quicktype-core/src/Type/TypeRef.ts @@ -1,9 +1,9 @@ -import { type TypeAttributes } from "../attributes/TypeAttributes"; -import { type BaseGraphRewriteBuilder } from "../GraphRewriting"; +import type { TypeAttributes } from "../attributes/TypeAttributes"; +import type { BaseGraphRewriteBuilder } from "../GraphRewriting"; import { assert } from "../support/Support"; -import { type Type } from "./Type"; -import { type TypeGraph } from "./TypeGraph"; +import type { Type } from "./Type"; +import type { TypeGraph } from "./TypeGraph"; const indexBits = 26; const indexMask = (1 << indexBits) - 1; @@ -28,20 +28,25 @@ export function typeRefIndex(tref: TypeRef): number { export function assertTypeRefGraph(tref: TypeRef, graph: TypeGraph): void { assert( ((tref >> indexBits) & serialMask) === (graph.serial & serialMask), - "Mixing the wrong type reference and graph" + "Mixing the wrong type reference and graph", ); } -function getGraph(graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder): TypeGraph { +function getGraph( + graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder, +): TypeGraph { if ("originalGraph" in graphOrBuilder) { return graphOrBuilder.originalGraph; } - // do not use `graphOrBuilder instanceof TypeGraph` to check if is TypeGraph to prevent import cycle + // do not use `graphOrBuilder instanceof TypeGraph` to check if is TypeGraph to prevent import cycle return graphOrBuilder; } -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)); @@ -49,7 +54,7 @@ export function derefTypeRef(tref: TypeRef, graphOrBuilder: TypeGraph | BaseGrap export function attributesForTypeRef( tref: TypeRef, - graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder + graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder, ): TypeAttributes { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); @@ -58,7 +63,7 @@ export function attributesForTypeRef( export function typeAndAttributesForTypeRef( tref: TypeRef, - graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder + graphOrBuilder: TypeGraph | BaseGraphRewriteBuilder, ): [Type, TypeAttributes] { const graph = getGraph(graphOrBuilder); assertTypeRefGraph(tref, graph); diff --git a/packages/quicktype-core/src/Type/TypeUtils.ts b/packages/quicktype-core/src/Type/TypeUtils.ts index ac1816c5..499f7c05 100644 --- a/packages/quicktype-core/src/Type/TypeUtils.ts +++ b/packages/quicktype-core/src/Type/TypeUtils.ts @@ -1,11 +1,20 @@ -import { EqualityMap, iterableFirst, setFilter, setSortBy, setUnion } from "collection-utils"; +import { + EqualityMap, + iterableFirst, + setFilter, + setSortBy, + setUnion, +} from "collection-utils"; -import { type StringTypes, stringTypesTypeAttributeKind } from "../attributes/StringTypes"; +import { + type StringTypes, + stringTypesTypeAttributeKind, +} from "../attributes/StringTypes"; import { type CombinationKind, type TypeAttributes, combineTypeAttributes, - emptyTypeAttributes + emptyTypeAttributes, } from "../attributes/TypeAttributes"; import { assert, assertNever, defined, panic } from "../support/Support"; @@ -20,7 +29,7 @@ import { type PrimitiveType, type SetOperationType, type Type, - UnionType + UnionType, } from "./Type"; export function assertIsObject(t: Type): ObjectType { @@ -41,11 +50,11 @@ export function assertIsClass(t: Type): ClassType { export function setOperationMembersRecursively( setOperations: T | T[], - combinationKind: CombinationKind | undefined + combinationKind: CombinationKind | undefined, ): [ReadonlySet, TypeAttributes]; 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; @@ -60,7 +69,11 @@ export function setOperationMembersRecursively( if (processedSetOperations.has(so)) return; processedSetOperations.add(so); if (combinationKind !== undefined) { - attributes = combineTypeAttributes(combinationKind, attributes, t.getAttributes()); + attributes = combineTypeAttributes( + combinationKind, + attributes, + t.getAttributes(), + ); } for (const m of so.members) { @@ -70,7 +83,11 @@ export function setOperationMembersRecursively( members.add(t); } else { if (combinationKind !== undefined) { - attributes = combineTypeAttributes(combinationKind, attributes, t.getAttributes()); + attributes = combineTypeAttributes( + combinationKind, + attributes, + t.getAttributes(), + ); } } } @@ -84,13 +101,15 @@ export function setOperationMembersRecursively( 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) { // FIXME: We shouldn't have to make a new set here once we got rid // of immutable. - const members = new Set(setOperationMembersRecursively(u, undefined)[0]); + const members = new Set( + setOperationMembersRecursively(u, undefined)[0], + ); if (include !== undefined) { if (!include(members)) continue; @@ -108,13 +127,16 @@ export function makeGroupsToFlatten( typeGroups.set(members, maybeSet); } - return Array.from(typeGroups.values()).map(ts => Array.from(ts)); + 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()), ); } @@ -127,11 +149,11 @@ export function isAnyOrNull(t: Type): boolean { // introduced. export function removeNullFromUnion( t: UnionType, - sortBy: boolean | ((t: Type) => string | number) = false + sortBy: boolean | ((t: Type) => string | number) = false, ): [PrimitiveType | null, ReadonlySet] { function sort(s: ReadonlySet): ReadonlySet { if (sortBy === false) return s; - if (sortBy === true) return setSortBy(s, m => m.kind); + if (sortBy === true) return setSortBy(s, (m) => m.kind); return setSortBy(s, sortBy); } @@ -140,10 +162,15 @@ export function removeNullFromUnion( return [null, sort(t.members)]; } - return [nullType as PrimitiveType, sort(setFilter(t.members, m => m.kind !== "null"))]; + 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()]; } @@ -166,7 +193,9 @@ 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]; @@ -190,22 +219,35 @@ export interface 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; + const enums = setFilter( + types, + (t) => t instanceof EnumType, + ) as Set as ReadonlySet; + const unions = setFilter( + types, + (t) => t instanceof UnionType, + ) as Set as ReadonlySet; 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))); + return setUnion( + ...Array.from(t.getNonAttributeChildren()).map((c) => + directlyReachableTypes(c, setForType), + ), + ); } export function directlyReachableSingleNamedType(type: Type): Type | undefined { - const definedTypes = directlyReachableTypes(type, t => { + const definedTypes = directlyReachableTypes(type, (t) => { if ( (!(t instanceof UnionType) && isNamedType(t)) || (t instanceof UnionType && nullableFromUnion(t) === null) @@ -215,13 +257,18 @@ export function directlyReachableSingleNamedType(type: Type): Type | undefined { return null; }); - assert(definedTypes.size <= 1, "Cannot have more than one defined type per top-level"); + assert( + definedTypes.size <= 1, + "Cannot have more than one defined type per top-level", + ); return iterableFirst(definedTypes); } export function stringTypesForType(t: PrimitiveType): StringTypes { assert(t.kind === "string", "Only strings can have string types"); - const stringTypes = stringTypesTypeAttributeKind.tryGetInAttributes(t.getAttributes()); + const stringTypes = stringTypesTypeAttributeKind.tryGetInAttributes( + t.getAttributes(), + ); if (stringTypes === undefined) { return panic("All strings must have a string type attribute"); } @@ -250,7 +297,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)) { @@ -268,16 +315,17 @@ export function matchTypeExhaustive( null: nullType, bool: boolType, integer: integerType, - double: doubleType + double: doubleType, }[kind]; if (f !== undefined) return f(t); return assertNever(f); - } else if (t instanceof ArrayType) return arrayType(t); - else if (t instanceof ClassType) return classType(t); - else if (t instanceof MapType) return mapType(t); - else if (t instanceof ObjectType) return objectType(t); - else if (t instanceof EnumType) return enumType(t); - else if (t instanceof UnionType) return unionType(t); + } + if (t instanceof ArrayType) return arrayType(t); + if (t instanceof ClassType) return classType(t); + if (t instanceof MapType) return mapType(t); + if (t instanceof ObjectType) return objectType(t); + if (t instanceof EnumType) return enumType(t); + if (t instanceof UnionType) return unionType(t); return panic(`Unknown type ${t.kind}`); } @@ -294,7 +342,7 @@ 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): never { return panic(`Unsupported type ${t.kind} in non-exhaustive match`); @@ -315,7 +363,7 @@ export function matchType( typeNotSupported, enumType, unionType, - transformedStringType ?? typeNotSupported + transformedStringType ?? typeNotSupported, ); } @@ -325,7 +373,7 @@ export function matchCompoundType( 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 { return; @@ -346,6 +394,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 be20b55e..5c1e0094 100644 --- a/packages/quicktype-core/src/UnifyClasses.ts +++ b/packages/quicktype-core/src/UnifyClasses.ts @@ -1,10 +1,23 @@ import { iterableFirst, setUnionInto } from "collection-utils"; -import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; -import { type BaseGraphRewriteBuilder, type GraphRewriteBuilder, type TypeLookerUp } from "./GraphRewriting"; +import { + type TypeAttributes, + combineTypeAttributes, + emptyTypeAttributes, +} from "./attributes/TypeAttributes"; +import type { + BaseGraphRewriteBuilder, + GraphRewriteBuilder, + TypeLookerUp, +} from "./GraphRewriting"; import { assert, defined, panic } from "./support/Support"; -import { type ClassProperty, type ObjectType, type Type, UnionType } from "./Type/Type"; -import { type TypeBuilder } from "./Type/TypeBuilder"; +import { + type ClassProperty, + type ObjectType, + type Type, + UnionType, +} from "./Type/Type"; +import type { TypeBuilder } from "./Type/TypeBuilder"; import { type TypeRef, derefTypeRef } from "./Type/TypeRef"; import { assertIsObject } from "./Type/TypeUtils"; import { TypeRefUnionAccumulator, UnionBuilder } from "./UnionBuilder"; @@ -12,18 +25,20 @@ import { TypeRefUnionAccumulator, UnionBuilder } from "./UnionBuilder"; 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(); + const lostTypeAttributes = false; + const propertyNames = new Set(); for (const o of clique) { setUnionInto(propertyNames, o.getProperties().keys()); } - let properties = Array.from(propertyNames).map(name => [name, new Set(), false] as [string, Set, boolean]); + const properties = Array.from(propertyNames).map( + (name) => [name, new Set(), false] as [string, Set, boolean], + ); let additionalProperties: Set | undefined = undefined; for (const o of clique) { - let additional = o.getAdditionalProperties(); + const additional = o.getAdditionalProperties(); if (additional !== undefined) { if (additionalProperties === undefined) { additionalProperties = new Set(); @@ -57,11 +72,18 @@ function getCliqueProperties( } const unifiedAdditionalProperties = - additionalProperties === undefined ? undefined : makePropertyType(additionalProperties); + additionalProperties === undefined + ? undefined + : makePropertyType(additionalProperties); - const unifiedPropertiesArray = properties.map(([name, types, isOptional]) => { - return [name, builder.makeClassProperty(makePropertyType(types), isOptional)] as [string, ClassProperty]; - }); + const unifiedPropertiesArray = properties.map( + ([name, types, isOptional]) => { + return [ + name, + builder.makeClassProperty(makePropertyType(types), isOptional), + ] as [string, ClassProperty]; + }, + ); const unifiedProperties = new Map(unifiedPropertiesArray); return [unifiedProperties, unifiedAdditionalProperties, lostTypeAttributes]; @@ -89,15 +111,23 @@ function countProperties(clique: ObjectType[]): { } } - return { hasProperties, hasAdditionalProperties, hasNonAnyAdditionalProperties }; + return { + hasProperties, + hasAdditionalProperties, + hasNonAnyAdditionalProperties, + }; } -export class UnifyUnionBuilder extends UnionBuilder { +export class UnifyUnionBuilder extends UnionBuilder< + BaseGraphRewriteBuilder, + TypeRef[], + TypeRef[] +> { 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); } @@ -105,50 +135,71 @@ export class UnifyUnionBuilder extends UnionBuilder assertIsObject(derefTypeRef(r, this.typeBuilder))); - const { hasProperties, hasAdditionalProperties, hasNonAnyAdditionalProperties } = countProperties(objectTypes); + const objectTypes = objectRefs.map((r) => + 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) + .filter((o) => o.getAdditionalProperties() !== undefined) + .map((o) => defined(o.getAdditionalProperties()).typeRef), ); setUnionInto(propertyTypes, additionalPropertyTypes); - return this.typeBuilder.getMapType(typeAttributes, this._unifyTypes(Array.from(propertyTypes))); - } else { - const [properties, additionalProperties, lostTypeAttributes] = getCliqueProperties( - objectTypes, - this.typeBuilder, - types => { - assert(types.size > 0, "Property has no type"); - return this._unifyTypes(Array.from(types).map(t => t.typeRef)); - } + return this.typeBuilder.getMapType( + typeAttributes, + this._unifyTypes(Array.from(propertyTypes)), ); + } else { + const [properties, additionalProperties, lostTypeAttributes] = + getCliqueProperties(objectTypes, this.typeBuilder, (types) => { + assert(types.size > 0, "Property has no type"); + return this._unifyTypes( + Array.from(types).map((t) => t.typeRef), + ); + }); if (lostTypeAttributes) { this.typeBuilder.setLostTypeAttributes(); } @@ -158,15 +209,18 @@ export class UnifyUnionBuilder extends UnionBuilder( typeBuilder: GraphRewriteBuilder, makeObjectTypes: boolean, makeClassesFixed: boolean, - conflateNumbers: boolean + conflateNumbers: boolean, ): UnionBuilder { - return new UnifyUnionBuilder(typeBuilder, makeObjectTypes, makeClassesFixed, trefs => - unifyTypes( - new Set(trefs.map(tref => derefTypeRef(tref, typeBuilder))), - emptyTypeAttributes, - typeBuilder, - unionBuilderForUnification(typeBuilder, makeObjectTypes, makeClassesFixed, conflateNumbers), - conflateNumbers - ) + return new UnifyUnionBuilder( + typeBuilder, + makeObjectTypes, + makeClassesFixed, + (trefs) => + unifyTypes( + new Set(trefs.map((tref) => derefTypeRef(tref, typeBuilder))), + emptyTypeAttributes, + typeBuilder, + unionBuilderForUnification( + typeBuilder, + makeObjectTypes, + makeClassesFixed, + conflateNumbers, + ), + conflateNumbers, + ), ); } @@ -205,9 +272,13 @@ export function unifyTypes( types: ReadonlySet, typeAttributes: TypeAttributes, typeBuilder: GraphRewriteBuilder, - unionBuilder: UnionBuilder, + unionBuilder: UnionBuilder< + TypeBuilder & TypeLookerUp, + TypeRef[], + TypeRef[] + >, conflateNumbers: boolean, - maybeForwardingRef?: TypeRef + maybeForwardingRef?: TypeRef, ): TypeRef { typeAttributes = typeBuilder.reconstituteTypeAttributes(typeAttributes); if (types.size === 0) { @@ -215,23 +286,44 @@ export function unifyTypes( } else if (types.size === 1) { const first = defined(iterableFirst(types)); if (!(first instanceof UnionType)) { - return typeBuilder.reconstituteTypeRef(first.typeRef, typeAttributes, maybeForwardingRef); + return typeBuilder.reconstituteTypeRef( + first.typeRef, + typeAttributes, + maybeForwardingRef, + ); } } - const typeRefs = Array.from(types).map(t => t.typeRef); - const maybeTypeRef = typeBuilder.lookupTypeRefs(typeRefs, maybeForwardingRef); + const typeRefs = Array.from(types).map((t) => t.typeRef); + const maybeTypeRef = typeBuilder.lookupTypeRefs( + typeRefs, + maybeForwardingRef, + ); if (maybeTypeRef !== undefined) { typeBuilder.addAttributes(maybeTypeRef, typeAttributes); return maybeTypeRef; } const accumulator = new TypeRefUnionAccumulator(conflateNumbers); - const nestedAttributes = typeBuilder.reconstituteTypeAttributes(accumulator.addTypes(types)); - typeAttributes = combineTypeAttributes("union", typeAttributes, nestedAttributes); + const nestedAttributes = typeBuilder.reconstituteTypeAttributes( + accumulator.addTypes(types), + ); + typeAttributes = combineTypeAttributes( + "union", + typeAttributes, + nestedAttributes, + ); - return typeBuilder.withForwardingRef(maybeForwardingRef, forwardingRef => { - typeBuilder.registerUnion(typeRefs, forwardingRef); - return unionBuilder.buildUnion(accumulator, false, typeAttributes, forwardingRef); - }); + return typeBuilder.withForwardingRef( + maybeForwardingRef, + (forwardingRef) => { + typeBuilder.registerUnion(typeRefs, forwardingRef); + return unionBuilder.buildUnion( + accumulator, + false, + typeAttributes, + forwardingRef, + ); + }, + ); } diff --git a/packages/quicktype-core/src/UnionBuilder.ts b/packages/quicktype-core/src/UnionBuilder.ts index bea77e36..d5ed2b03 100644 --- a/packages/quicktype-core/src/UnionBuilder.ts +++ b/packages/quicktype-core/src/UnionBuilder.ts @@ -1,12 +1,20 @@ -import { mapMap, mapMerge, mapUpdateInto, setUnionInto } from "collection-utils"; +import { + mapMap, + mapMerge, + mapUpdateInto, + setUnionInto, +} from "collection-utils"; -import { StringTypes, stringTypesTypeAttributeKind } from "./attributes/StringTypes"; +import { + StringTypes, + stringTypesTypeAttributeKind, +} from "./attributes/StringTypes"; import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes, increaseTypeAttributesDistance, - makeTypeAttributesInferred + makeTypeAttributesInferred, } from "./attributes/TypeAttributes"; import { assert, assertNever, defined, panic } from "./support/Support"; import { @@ -15,10 +23,10 @@ import { type Type, type TypeKind, UnionType, - isPrimitiveTypeKind + isPrimitiveTypeKind, } from "./Type"; -import { type TypeBuilder } from "./Type/TypeBuilder"; -import { type TypeRef } from "./Type/TypeRef"; +import type { TypeBuilder } from "./Type/TypeBuilder"; +import type { TypeRef } from "./Type/TypeRef"; import { matchTypeExhaustive } from "./Type/TypeUtils"; // FIXME: This interface is badly designed. All the properties @@ -44,7 +52,7 @@ type TypeAttributeMapBuilder = Map; function addAttributes( accumulatorAttributes: TypeAttributes | undefined, - newAttributes: TypeAttributes + newAttributes: TypeAttributes, ): TypeAttributes { if (accumulatorAttributes === undefined) return newAttributes; return combineTypeAttributes("union", accumulatorAttributes, newAttributes); @@ -53,15 +61,18 @@ function addAttributes( function setAttributes( attributeMap: TypeAttributeMap, kind: T, - newAttributes: TypeAttributes + newAttributes: TypeAttributes, ): void { - attributeMap.set(kind, addAttributes(attributeMap.get(kind), newAttributes)); + attributeMap.set( + kind, + addAttributes(attributeMap.get(kind), newAttributes), + ); } function addAttributesToBuilder( builder: TypeAttributeMapBuilder, kind: T, - newAttributes: TypeAttributes + newAttributes: TypeAttributes, ): void { let arr = builder.get(kind); if (arr === undefined) { @@ -72,20 +83,30 @@ function addAttributesToBuilder( arr.push(newAttributes); } -function buildTypeAttributeMap(builder: TypeAttributeMapBuilder): TypeAttributeMap { - return mapMap(builder, arr => combineTypeAttributes("union", arr)); +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); } -export class UnionAccumulator implements UnionTypeProvider { - private readonly _nonStringTypeAttributes: TypeAttributeMapBuilder = new Map(); +export class UnionAccumulator + implements UnionTypeProvider +{ + private readonly _nonStringTypeAttributes: TypeAttributeMapBuilder = + new Map(); - private readonly _stringTypeAttributes: TypeAttributeMapBuilder = new Map(); + private readonly _stringTypeAttributes: TypeAttributeMapBuilder = + new Map(); public readonly arrayData: TArray[] = []; @@ -99,7 +120,8 @@ 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); + addAttributesToBuilder( + this._stringTypeAttributes, + "string", + attributes, + ); return; } - addAttributesToBuilder(this._nonStringTypeAttributes, "enum", attributes); + addAttributesToBuilder( + this._nonStringTypeAttributes, + "enum", + attributes, + ); setUnionInto(this._enumCases, cases); } @@ -188,7 +254,11 @@ export class UnionAccumulator implements UnionTypeProvider implements UnionTypeProvider { - assert(!(this.have("enum") && this.have("string")), "We can't have both strings and enums in the same union"); + assert( + !(this.have("enum") && this.have("string")), + "We can't have both strings and enums in the same union", + ); - let merged = mapMerge( + const merged = mapMerge( buildTypeAttributeMap(this._nonStringTypeAttributes), - buildTypeAttributeMap(this._stringTypeAttributes) + buildTypeAttributeMap(this._stringTypeAttributes), ); if (merged.size === 0) { - return new Map([["none", emptyTypeAttributes] as [TypeKind, TypeAttributes]]); + return new Map([ + ["none", emptyTypeAttributes] as [TypeKind, TypeAttributes], + ]); } if (this._nonStringTypeAttributes.has("any")) { - assert(this._lostTypeAttributes, "This had to be set when we added 'any'"); + assert( + this._lostTypeAttributes, + "This had to be set when we added 'any'", + ); - const allAttributes = combineTypeAttributes("union", Array.from(merged.values())); - return new Map([["any", allAttributes] as [TypeKind, TypeAttributes]]); + const allAttributes = combineTypeAttributes( + "union", + Array.from(merged.values()), + ); + return new Map([ + ["any", allAttributes] as [TypeKind, TypeAttributes], + ]); } - if (this._conflateNumbers && this.have("integer") && this.have("double")) { + if ( + this._conflateNumbers && + this.have("integer") && + this.have("double") + ) { moveAttributes(merged, "integer", "double"); } @@ -239,7 +326,9 @@ class FauxUnion { type UnionOrFaux = UnionType | FauxUnion; -function attributesForTypes(types: Iterable): [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. @@ -251,7 +340,11 @@ 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) { @@ -266,9 +359,13 @@ 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), + ); } } } @@ -280,15 +377,22 @@ function attributesForTypes(types: Iterable): [ReadonlyMap { - const singleAncestors = Array.from(unionForType).filter(u => defined(typesForUnion.get(u)).size === 1); - assert( - singleAncestors.every(u => defined(typesForUnion.get(u)).has(t)), - "We messed up bookkeeping" + const singleAncestors = Array.from(unionForType).filter( + (u) => defined(typesForUnion.get(u)).size === 1, + ); + assert( + singleAncestors.every((u) => defined(typesForUnion.get(u)).has(t)), + "We messed up bookkeeping", + ); + const inheritedAttributes = singleAncestors.map((u) => + u.getAttributes(), + ); + return combineTypeAttributes( + "union", + [t.getAttributes()].concat(inheritedAttributes), ); - const inheritedAttributes = singleAncestors.map(u => u.getAttributes()); - return combineTypeAttributes("union", [t.getAttributes()].concat(inheritedAttributes)); }); - const unionAttributes = Array.from(unions).map(u => { + const unionAttributes = Array.from(unions).map((u) => { const t = typesForUnion.get(u); if (t !== undefined && t.size === 1) { return emptyTypeAttributes; @@ -305,32 +409,40 @@ function attributesForTypes(types: Iterable): [ReadonlyMap { +export class TypeRefUnionAccumulator extends UnionAccumulator< + TypeRef, + TypeRef +> { // 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 { matchTypeExhaustive( t, - _noneType => this.addNone(attributes), - _anyType => this.addAny(attributes), - _nullType => this.addPrimitive("null", attributes), - _boolType => this.addPrimitive("bool", attributes), - _integerType => this.addPrimitive("integer", attributes), - _doubleType => this.addPrimitive("double", attributes), - _stringType => this.addStringType("string", attributes), - arrayType => this.addArray(arrayType.items.typeRef, attributes), - classType => this.addObject(classType.typeRef, attributes), - mapType => this.addObject(mapType.typeRef, attributes), - objectType => this.addObject(objectType.typeRef, attributes), + (_noneType) => this.addNone(attributes), + (_anyType) => this.addAny(attributes), + (_nullType) => this.addPrimitive("null", attributes), + (_boolType) => this.addPrimitive("bool", attributes), + (_integerType) => this.addPrimitive("integer", attributes), + (_doubleType) => this.addPrimitive("double", attributes), + (_stringType) => this.addStringType("string", attributes), + (arrayType) => this.addArray(arrayType.items.typeRef, attributes), + (classType) => this.addObject(classType.typeRef, attributes), + (mapType) => this.addObject(mapType.typeRef, attributes), + (objectType) => this.addObject(objectType.typeRef, attributes), // FIXME: We're not carrying counts, so this is not correct if we do enum // inference. JSON Schema input uses this case, however, without enum // inference, which is fine, but still a bit ugly. - enumType => this.addEnum(enumType.cases, attributes), - _unionType => { - return panic("The unions should have been eliminated in attributesForTypesInUnion"); + (enumType) => this.addEnum(enumType.cases, attributes), + (_unionType) => { + return panic( + "The unions should have been eliminated in attributesForTypesInUnion", + ); }, - transformedStringType => - this.addStringType(transformedStringType.kind as PrimitiveStringTypeKind, attributes) + (transformedStringType) => + this.addStringType( + transformedStringType.kind as PrimitiveStringTypeKind, + attributes, + ), ); } @@ -344,41 +456,70 @@ export class TypeRefUnionAccumulator extends UnionAccumulator } } -export abstract class UnionBuilder { +export abstract class UnionBuilder< + TBuilder extends TypeBuilder, + TArrayData, + TObjectData, +> { public constructor(protected readonly typeBuilder: TBuilder) {} protected abstract makeObject( objects: TObjectData, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef; protected abstract makeArray( arrays: TArrayData, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef; private makeTypeOfKind( typeProvider: UnionTypeProvider, kind: TypeKind, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { switch (kind) { case "string": - return this.typeBuilder.getStringType(typeAttributes, undefined, forwardingRef); + return this.typeBuilder.getStringType( + typeAttributes, + undefined, + forwardingRef, + ); case "enum": - return this.typeBuilder.getEnumType(typeAttributes, typeProvider.enumCases, forwardingRef); + return this.typeBuilder.getEnumType( + typeAttributes, + typeProvider.enumCases, + forwardingRef, + ); case "object": - return this.makeObject(typeProvider.objectData, typeAttributes, forwardingRef); + return this.makeObject( + typeProvider.objectData, + typeAttributes, + forwardingRef, + ); case "array": - return this.makeArray(typeProvider.arrayData, typeAttributes, forwardingRef); + return this.makeArray( + typeProvider.arrayData, + typeAttributes, + forwardingRef, + ); default: if (isPrimitiveTypeKind(kind)) { - return this.typeBuilder.getPrimitiveType(kind, typeAttributes, forwardingRef); + return this.typeBuilder.getPrimitiveType( + kind, + typeAttributes, + forwardingRef, + ); } - if (kind === "union" || kind === "class" || kind === "map" || kind === "intersection") { + if ( + kind === "union" || + kind === "class" || + kind === "map" || + kind === "intersection" + ) { return panic(`getMemberKinds() shouldn't return ${kind}`); } @@ -390,7 +531,7 @@ export abstract class UnionBuilder, unique: boolean, typeAttributes: TypeAttributes, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { const kinds = typeProvider.getMemberKinds(); @@ -407,19 +548,35 @@ export abstract class UnionBuilder { } } -export const accessorNamesTypeAttributeKind: TypeAttributeKind = new AccessorNamesTypeAttributeKind(); +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 +62,43 @@ 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 { - const accessors = accessorNamesTypeAttributeKind.tryGetInAttributes(o.getAttributes()); +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); + if (accessors === undefined) return mapMap(map, (_) => undefined); return mapMap(map, (_cp, n) => lookupKey(accessors, n, language)); } -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 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( names: Map, - original: string + original: string, ): [string | undefined, boolean] { const maybeName = names.get(original); if (maybeName === undefined) return [undefined, false]; @@ -79,7 +112,9 @@ export function getAccessorName( // That way, no matter how the types are recombined, if we find a union member, we can look // 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> { +class UnionIdentifierTypeAttributeKind extends TypeAttributeKind< + ReadonlySet +> { public constructor() { super("unionIdentifier"); } @@ -93,23 +128,30 @@ class UnionIdentifierTypeAttributeKind extends TypeAttributeKind> = - new UnionIdentifierTypeAttributeKind(); +export const unionIdentifierTypeAttributeKind: TypeAttributeKind< + ReadonlySet +> = new UnionIdentifierTypeAttributeKind(); let nextUnionIdentifier = 0; export function makeUnionIdentifierAttribute(): TypeAttributes { - const attributes = unionIdentifierTypeAttributeKind.makeAttributes(new Set([nextUnionIdentifier])); + const attributes = unionIdentifierTypeAttributeKind.makeAttributes( + new Set([nextUnionIdentifier]), + ); nextUnionIdentifier += 1; return attributes; } -class UnionMemberNamesTypeAttributeKind extends TypeAttributeKind> { +class UnionMemberNamesTypeAttributeKind extends TypeAttributeKind< + Map +> { public constructor() { super("unionMemberNames"); } - public combine(arr: Array>): Map { + public combine( + arr: Array>, + ): Map { const result = new Map(); for (const m of arr) { mapMergeInto(result, m); @@ -119,20 +161,34 @@ class UnionMemberNamesTypeAttributeKind extends TypeAttributeKind> = - new UnionMemberNamesTypeAttributeKind(); +export const unionMemberNamesTypeAttributeKind: TypeAttributeKind< + Map +> = new UnionMemberNamesTypeAttributeKind(); -export function makeUnionMemberNamesAttribute(unionAttributes: TypeAttributes, entry: AccessorEntry): TypeAttributes { - const identifiers = defined(unionIdentifierTypeAttributeKind.tryGetInAttributes(unionAttributes)); - const map = mapFromIterable(identifiers, _ => entry); +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] { - const identifiers = unionIdentifierTypeAttributeKind.tryGetInAttributes(u.getAttributes()); +export function unionMemberName( + u: UnionType, + member: Type, + language: string, +): [string | undefined, boolean] { + const identifiers = unionIdentifierTypeAttributeKind.tryGetInAttributes( + u.getAttributes(), + ); if (identifiers === undefined) return [undefined, false]; - const memberNames = unionMemberNamesTypeAttributeKind.tryGetInAttributes(member.getAttributes()); + const memberNames = unionMemberNamesTypeAttributeKind.tryGetInAttributes( + member.getAttributes(), + ); if (memberNames === undefined) return [undefined, false]; const names = new Set(); @@ -164,11 +220,15 @@ export function unionMemberName(u: UnionType, member: Type, language: string): [ isFixed = false; } - messageAssert(size === 1, "SchemaMoreThanOneUnionMemberName", { names: Array.from(names) }); + messageAssert(size === 1, "SchemaMoreThanOneUnionMemberName", { + names: Array.from(names), + }); return [first, isFixed]; } -function isAccessorEntry(x: unknown): x is string | { [language: string]: string } { +function isAccessorEntry( + x: unknown, +): x is string | { [language: string]: string } { if (typeof x === "string") { return true; } @@ -176,7 +236,9 @@ function isAccessorEntry(x: unknown): x is string | { [language: string]: string return isStringMap(x, (v: unknown): 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); } @@ -191,24 +253,35 @@ 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"]; if (maybeAccessors === undefined) return undefined; if (cases === undefined) { - return { forType: accessorNamesTypeAttributeKind.makeAttributes(makeAccessorNames(maybeAccessors)) }; + return { + forType: accessorNamesTypeAttributeKind.makeAttributes( + makeAccessorNames(maybeAccessors), + ), + }; } else { const identifierAttribute = makeUnionIdentifierAttribute(); const accessors = checkArray(maybeAccessors, isAccessorEntry); - messageAssert(cases.length === accessors.length, "SchemaWrongAccessorEntryArrayLength", { - operation: "oneOf", - ref: canonicalRef.push("oneOf") - }); - const caseAttributes = accessors.map(accessor => - makeUnionMemberNamesAttribute(identifierAttribute, makeAccessorEntry(accessor)) + messageAssert( + cases.length === accessors.length, + "SchemaWrongAccessorEntryArrayLength", + { + operation: "oneOf", + ref: canonicalRef.push("oneOf"), + }, + ); + const caseAttributes = accessors.map((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 09fb7956..3266e9bc 100644 --- a/packages/quicktype-core/src/attributes/Constraints.ts +++ b/packages/quicktype-core/src/attributes/Constraints.ts @@ -1,8 +1,12 @@ -import { type JSONSchemaAttributes, type JSONSchemaType, type Ref } from "../input/JSONSchemaInput"; -import { type JSONSchema } from "../input/JSONSchemaStore"; +import type { + JSONSchemaAttributes, + JSONSchemaType, + 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 type { Type, TypeKind } from "../Type"; import { TypeAttributeKind } from "./TypeAttributes"; @@ -11,7 +15,9 @@ import { TypeAttributeKind } from "./TypeAttributes"; // `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 }); @@ -29,7 +35,7 @@ export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind, private _minSchemaProperty: string, - private _maxSchemaProperty: string + private _maxSchemaProperty: string, ) { super(name); } @@ -86,7 +92,11 @@ export class MinMaxConstraintTypeAttributeKind extends TypeAttributeKind = new MinMaxConstraintTypeAttributeKind( - "minMax", - new Set(["integer", "double"]), - "minimum", - "maximum" -); +export const minMaxTypeAttributeKind: TypeAttributeKind = + new MinMaxConstraintTypeAttributeKind( + "minMax", + new Set(["integer", "double"]), + "minimum", + "maximum", + ); -export const minMaxLengthTypeAttributeKind: TypeAttributeKind = new MinMaxConstraintTypeAttributeKind( - "minMaxLength", - new Set(["string"]), - "minLength", - "maxLength" -); +export const minMaxLengthTypeAttributeKind: TypeAttributeKind = + new MinMaxConstraintTypeAttributeKind( + "minMaxLength", + new Set(["string"]), + "minLength", + "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; @@ -139,7 +155,7 @@ function producer(schema: JSONSchema, minProperty: string, maxProperty: string): export function minMaxAttributeProducer( schema: JSONSchema, _ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!types.has("number") && !types.has("integer")) return undefined; @@ -151,13 +167,16 @@ export function minMaxAttributeProducer( export function minMaxLengthAttributeProducer( schema: JSONSchema, _ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!types.has("string")) return undefined; const maybeMinMaxLength = producer(schema, "minLength", "maxLength"); if (maybeMinMaxLength === undefined) return undefined; - return { forString: minMaxLengthTypeAttributeKind.makeAttributes(maybeMinMaxLength) }; + return { + forString: + minMaxLengthTypeAttributeKind.makeAttributes(maybeMinMaxLength), + }; } export function minMaxValueForType(t: Type): MinMaxConstraint | undefined { @@ -179,7 +198,7 @@ export class PatternTypeAttributeKind extends TypeAttributeKind { public combine(arr: string[]): string { assert(arr.length > 0); - return arr.map(p => `(${p})`).join("|"); + return arr.map((p) => `(${p})`).join("|"); } public intersect(_arr: string[]): string | undefined { @@ -191,18 +210,23 @@ export class PatternTypeAttributeKind extends TypeAttributeKind { return undefined; } - public 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; } } -export const patternTypeAttributeKind: TypeAttributeKind = new PatternTypeAttributeKind(); +export const patternTypeAttributeKind: TypeAttributeKind = + new PatternTypeAttributeKind(); 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; diff --git a/packages/quicktype-core/src/attributes/Description.ts b/packages/quicktype-core/src/attributes/Description.ts index 26600383..e6a568d8 100644 --- a/packages/quicktype-core/src/attributes/Description.ts +++ b/packages/quicktype-core/src/attributes/Description.ts @@ -5,29 +5,31 @@ import { mapMergeWithInto, setSubtract, setUnion, - setUnionManyInto + setUnionManyInto, } from "collection-utils"; -import { - type JSONSchemaAttributes, - type JSONSchemaType, - type Ref +import type { + JSONSchemaAttributes, + JSONSchemaType, + Ref, } from "../input/JSONSchemaInput"; -import { type JSONSchema } from "../input/JSONSchemaStore"; +import type { JSONSchema } from "../input/JSONSchemaStore"; import { type PathElement, PathElementKind } from "../input/PathElement"; -import { type Type } from "../Type/Type"; +import type { Type } from "../Type/Type"; import { TypeAttributeKind, emptyTypeAttributes } from "./TypeAttributes"; export function addDescriptionToSchema( schema: { [name: string]: unknown }, - description: Iterable | undefined + description: Iterable | undefined, ): void { if (description === undefined) return; schema.description = Array.from(description).join("\n"); } -class DescriptionTypeAttributeKind extends TypeAttributeKind> { +class DescriptionTypeAttributeKind extends TypeAttributeKind< + ReadonlySet +> { public constructor() { super("description"); } @@ -40,7 +42,11 @@ class DescriptionTypeAttributeKind extends TypeAttributeKind return undefined; } - public addToSchema(schema: { [name: string]: unknown }, _t: Type, attrs: ReadonlySet): void { + public addToSchema( + schema: { [name: string]: unknown }, + _t: Type, + attrs: ReadonlySet, + ): void { addDescriptionToSchema(schema, attrs); } @@ -59,14 +65,20 @@ class DescriptionTypeAttributeKind extends TypeAttributeKind } } -export const descriptionTypeAttributeKind: TypeAttributeKind> = new DescriptionTypeAttributeKind(); +export const descriptionTypeAttributeKind: TypeAttributeKind< + ReadonlySet +> = new DescriptionTypeAttributeKind(); -class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind>> { +class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind< + Map> +> { public constructor() { super("propertyDescriptions"); } - public combine(attrs: Array>>): Map> { + public combine( + attrs: Array>>, + ): Map> { // FIXME: Implement this with mutable sets const result = new Map>(); for (const attr of attrs) { @@ -80,14 +92,17 @@ class PropertyDescriptionsTypeAttributeKind extends TypeAttributeKind>): string | undefined { + public stringify( + propertyDescriptions: Map>, + ): string | undefined { if (propertyDescriptions.size === 0) return undefined; return `prop descs: ${propertyDescriptions.size}`; } } -export const propertyDescriptionsTypeAttributeKind: TypeAttributeKind>> = - new PropertyDescriptionsTypeAttributeKind(); +export const propertyDescriptionsTypeAttributeKind: TypeAttributeKind< + Map> +> = new PropertyDescriptionsTypeAttributeKind(); function isPropertiesKey(el: PathElement): boolean { return el.kind === PathElementKind.KeyOrIndex && el.key === "properties"; @@ -96,7 +111,7 @@ function isPropertiesKey(el: PathElement): boolean { export function descriptionAttributeProducer( schema: JSONSchema, ref: Ref, - types: Set + types: Set, ): JSONSchemaAttributes | undefined { if (!(typeof schema === "object")) return undefined; @@ -113,23 +128,35 @@ export function descriptionAttributeProducer( ) { const maybeDescription = schema.description; if (typeof maybeDescription === "string") { - description = descriptionTypeAttributeKind.makeAttributes(new Set([maybeDescription])); + description = descriptionTypeAttributeKind.makeAttributes( + new Set([maybeDescription]), + ); } } if (types.has("object") && typeof schema.properties === "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]); + 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]); + } } - } - return undefined; - }); + return undefined; + }, + ); if (propertyDescriptions.size > 0) { - propertyDescription = propertyDescriptionsTypeAttributeKind.makeAttributes(propertyDescriptions); + propertyDescription = + propertyDescriptionsTypeAttributeKind.makeAttributes( + propertyDescriptions, + ); } } diff --git a/packages/quicktype-core/src/attributes/EnumValues.ts b/packages/quicktype-core/src/attributes/EnumValues.ts index 6f59630a..6c1c8319 100644 --- a/packages/quicktype-core/src/attributes/EnumValues.ts +++ b/packages/quicktype-core/src/attributes/EnumValues.ts @@ -1,10 +1,18 @@ import { mapMap } from "collection-utils"; -import { type JSONSchemaAttributes, type JSONSchemaType, type Ref } from "../input/JSONSchemaInput"; -import { type JSONSchema } from "../input/JSONSchemaStore"; -import { type EnumType } from "../Type/Type"; +import type { + JSONSchemaAttributes, + JSONSchemaType, + Ref, +} from "../input/JSONSchemaInput"; +import type { JSONSchema } from "../input/JSONSchemaStore"; +import type { EnumType } from "../Type/Type"; -import { type AccessorNames, lookupKey, makeAccessorNames } from "./AccessorNames"; +import { + type AccessorNames, + lookupKey, + makeAccessorNames, +} from "./AccessorNames"; import { TypeAttributeKind } from "./TypeAttributes"; class EnumValuesTypeAttributeKind extends TypeAttributeKind { @@ -17,18 +25,25 @@ class EnumValuesTypeAttributeKind extends TypeAttributeKind { } } -export const enumValuesTypeAttributeKind: TypeAttributeKind = new EnumValuesTypeAttributeKind(); +export const enumValuesTypeAttributeKind: TypeAttributeKind = + new EnumValuesTypeAttributeKind(); -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 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( schema: JSONSchema, _canonicalRef: Ref | undefined, - _types: Set + _types: Set, ): JSONSchemaAttributes | undefined { if (typeof schema !== "object") return undefined; @@ -36,5 +51,9 @@ export function enumValuesAttributeProducer( if (maybeEnumValues === undefined) return undefined; - return { forType: enumValuesTypeAttributeKind.makeAttributes(makeAccessorNames(maybeEnumValues)) }; + return { + forType: enumValuesTypeAttributeKind.makeAttributes( + makeAccessorNames(maybeEnumValues), + ), + }; } diff --git a/packages/quicktype-core/src/attributes/StringTypes.ts b/packages/quicktype-core/src/attributes/StringTypes.ts index 742f3122..ea890bd0 100644 --- a/packages/quicktype-core/src/attributes/StringTypes.ts +++ b/packages/quicktype-core/src/attributes/StringTypes.ts @@ -7,23 +7,32 @@ import { mapMap, mapMergeWithInto, setIntersect, - setUnionInto + setUnionInto, } from "collection-utils"; -import { type DateTimeRecognizer } from "../DateTime"; +import type { DateTimeRecognizer } from "../DateTime"; import { assert, defined } from "../support/Support"; -import { type TransformedStringTypeKind } from "../Type/TransformedStringType"; -import { type StringTypeMapping, stringTypeMappingGet } from "../Type/TypeBuilderUtils"; +import type { TransformedStringTypeKind } from "../Type/TransformedStringType"; +import { + type StringTypeMapping, + stringTypeMappingGet, +} from "../Type/TypeBuilderUtils"; import { TypeAttributeKind } from "./TypeAttributes"; export class StringTypes { - public static readonly unrestricted: StringTypes = new StringTypes(undefined, new Set()); + public static readonly unrestricted: StringTypes = new StringTypes( + undefined, + new Set(), + ); 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()); + return new StringTypes( + new Map([[s, count] as [string, number]]), + new Set(), + ); } public static fromCases(cases: string[]): StringTypes { @@ -32,16 +41,22 @@ export class StringTypes { caseMap[s] = 1; } - return new StringTypes(new Map(cases.map(s => [s, 1] as [string, number])), new Set()); + return new StringTypes( + new Map(cases.map((s) => [s, 1] as [string, number])), + new Set(), + ); } // undefined means no restrictions public constructor( public readonly cases: ReadonlyMap | undefined, - public readonly transformations: ReadonlySet + public readonly transformations: ReadonlySet, ) { if (cases === undefined) { - assert(transformations.size === 0, "We can't have an unrestricted string that also allows transformations"); + assert( + transformations.size === 0, + "We can't have an unrestricted string that also allows transformations", + ); } } @@ -67,7 +82,10 @@ export class StringTypes { return new StringTypes(cases, transformations); } - public intersect(othersArray: StringTypes[], startIndex: number): StringTypes { + public intersect( + othersArray: StringTypes[], + startIndex: number, + ): StringTypes { let cases = this.cases; let transformations = this.transformations; @@ -75,21 +93,30 @@ export class StringTypes { const other = othersArray[i]; if (cases === undefined) { - cases = definedMap(other.cases, m => new Map(m)); + cases = definedMap(other.cases, (m) => new Map(m)); } else if (other.cases !== undefined) { const thisCases = cases; const otherCases = other.cases; - const intersects = setIntersect(thisCases.keys(), new Set(otherCases.keys())); - const entries = intersects.size > 0 ? intersects.entries() : new Set(thisCases.keys()).entries(); - cases = mapMap(entries, k => { + const intersects = setIntersect( + thisCases.keys(), + new Set(otherCases.keys()), + ); + const entries = + intersects.size > 0 + ? intersects.entries() + : new Set(thisCases.keys()).entries(); + cases = mapMap(entries, (k) => { const thisValue = defined(thisCases.get(k)); const otherValue = otherCases.get(k) ?? Math.min(); return Math.min(thisValue, otherValue); }); } - transformations = setIntersect(transformations, other.transformations); + transformations = setIntersect( + transformations, + other.transformations, + ); } return new StringTypes(cases, transformations); @@ -110,7 +137,10 @@ export class StringTypes { public equals(other: T): boolean { if (!(other instanceof StringTypes)) return false; - return areEqual(this.cases, other.cases) && areEqual(this.transformations, other.transformations); + return ( + areEqual(this.cases, other.cases) && + areEqual(this.transformations, other.transformations) + ); } public hashCode(): number { @@ -130,7 +160,9 @@ export class StringTypes { if (firstKey === undefined) { parts.push("enum with no cases"); } else { - parts.push(`${enumCases.size.toString()} enums: ${firstKey} (${enumCases.get(firstKey)}), ...`); + parts.push( + `${enumCases.size.toString()} enums: ${firstKey} (${enumCases.get(firstKey)}), ...`, + ); } } @@ -170,7 +202,8 @@ class StringTypesTypeAttributeKind extends TypeAttributeKind { } } -export const stringTypesTypeAttributeKind: TypeAttributeKind = new StringTypesTypeAttributeKind(); +export const stringTypesTypeAttributeKind: TypeAttributeKind = + new StringTypesTypeAttributeKind(); const INTEGER_STRING = /^(0|-?[1-9]\d*)$/; // We're restricting numbers to what's representable as 32 bit @@ -183,7 +216,7 @@ function isIntegerString(s: string): boolean { return false; } - const i = parseInt(s, 10); + const i = Number.parseInt(s, 10); return i >= MIN_INTEGER_STRING && i <= MAX_INTEGER_STRING; } @@ -211,23 +244,30 @@ function isURI(s: string): boolean { */ export function inferTransformedStringTypeKindForString( s: string, - recognizer: DateTimeRecognizer + recognizer: DateTimeRecognizer, ): TransformedStringTypeKind | undefined { - if (s.length === 0 || !"0123456789-abcdefth".includes(s[0])) return undefined; + if (s.length === 0 || !"0123456789-abcdefth".includes(s[0])) + return undefined; if (recognizer.isDate(s)) { return "date"; - } else if (recognizer.isTime(s)) { + } + if (recognizer.isTime(s)) { return "time"; - } else if (recognizer.isDateTime(s)) { + } + if (recognizer.isDateTime(s)) { return "date-time"; - } else if (isIntegerString(s)) { + } + if (isIntegerString(s)) { return "integer-string"; - } else if (s === "false" || s === "true") { + } + if (s === "false" || s === "true") { return "bool-string"; - } else if (isUUID(s)) { + } + if (isUUID(s)) { return "uuid"; - } else if (isURI(s)) { + } + if (isURI(s)) { return "uri"; } diff --git a/packages/quicktype-core/src/attributes/TypeAttributes.ts b/packages/quicktype-core/src/attributes/TypeAttributes.ts index e8a3a61c..069377e8 100644 --- a/packages/quicktype-core/src/attributes/TypeAttributes.ts +++ b/packages/quicktype-core/src/attributes/TypeAttributes.ts @@ -1,8 +1,13 @@ -import { hashString, mapFilter, mapFilterMap, mapTranspose } from "collection-utils"; +import { + hashString, + mapFilter, + mapFilterMap, + mapTranspose, +} from "collection-utils"; -import { type BaseGraphRewriteBuilder } from "../GraphRewriting"; +import type { BaseGraphRewriteBuilder } from "../GraphRewriting"; import { assert, panic } from "../support/Support"; -import { type Type, type TypeKind } from "../Type"; +import type { Type, TypeKind } from "../Type"; export class TypeAttributeKind { public constructor(public readonly name: string) {} @@ -27,7 +32,11 @@ export class TypeAttributeKind { return attrs; } - public addToSchema(_schema: { [name: string]: unknown }, _t: Type, _attrs: T): void { + public addToSchema( + _schema: { [name: string]: unknown }, + _t: Type, + _attrs: T, + ): void { return; } @@ -47,7 +56,10 @@ export class TypeAttributeKind { return false; } - public reconstitute(_builder: TBuilder, a: T): T { + public reconstitute( + _builder: TBuilder, + a: T, + ): T { return a; } @@ -65,7 +77,10 @@ export class TypeAttributeKind { return new Map(a).set(this, value); } - public 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,7 +92,10 @@ export class TypeAttributeKind { return this.setInAttributes(a, modified); } - public 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); } @@ -107,12 +125,19 @@ 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( + 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[]; @@ -143,10 +168,14 @@ 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 f5d96a7a..dbc583c3 100644 --- a/packages/quicktype-core/src/attributes/TypeNames.ts +++ b/packages/quicktype-core/src/attributes/TypeNames.ts @@ -1,4 +1,10 @@ -import { definedMap, iterableFirst, iterableSkip, setMap, setUnionInto } from "collection-utils"; +import { + definedMap, + iterableFirst, + iterableSkip, + setMap, + setUnionInto, +} from "collection-utils"; import * as pluralize from "pluralize"; import { Chance } from "../support/Chance"; @@ -33,7 +39,7 @@ export type NameOrNames = string | TypeNames; // 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 { - let originalFirst = iterableFirst(names); + const originalFirst = iterableFirst(names); if (originalFirst === undefined) { return panic("Named type has no names"); } @@ -42,10 +48,10 @@ function combineNames(names: ReadonlySet): string { return originalFirst; } - const namesSet = setMap(names, s => + const namesSet = setMap(names, (s) => splitIntoWords(s) - .map(w => w.word.toLowerCase()) - .join("_") + .map((w) => w.word.toLowerCase()) + .join("_"), ); const first = defined(iterableFirst(namesSet)); if (namesSet.size === 1) { @@ -73,7 +79,8 @@ function combineNames(names: ReadonlySet): string { } const prefix = prefixLength > 2 ? first.slice(0, prefixLength) : ""; - const suffix = suffixLength > 2 ? first.slice(first.length - suffixLength) : ""; + const suffix = + suffixLength > 2 ? first.slice(first.length - suffixLength) : ""; const combined = prefix + suffix; if (combined.length > 2) { return combined; @@ -88,13 +95,16 @@ export abstract class TypeNames { public static makeWithDistance( names: ReadonlySet, alternativeNames: ReadonlySet | undefined, - distance: number + distance: number, ): TypeNames { if (names.size >= tooManyNamesThreshold) { return new TooManyTypeNames(distance); } - if (alternativeNames === undefined || alternativeNames.size > tooManyNamesThreshold) { + if ( + alternativeNames === undefined || + alternativeNames.size > tooManyNamesThreshold + ) { alternativeNames = undefined; } @@ -104,9 +114,13 @@ export abstract class TypeNames { public static make( names: ReadonlySet, alternativeNames: ReadonlySet | undefined, - areInferred: boolean + areInferred: boolean, ): TypeNames { - return TypeNames.makeWithDistance(names, alternativeNames, areInferred ? 1 : 0); + return TypeNames.makeWithDistance( + names, + alternativeNames, + areInferred ? 1 : 0, + ); } public constructor(public readonly distance: number) {} @@ -119,7 +133,10 @@ export abstract class TypeNames { public abstract get combinedName(): string; public abstract get proposedNames(): ReadonlySet; - public abstract add(namesArray: TypeNames[], startIndex?: number): TypeNames; + public abstract add( + namesArray: TypeNames[], + startIndex?: number, + ): TypeNames; public abstract clearInferred(): TypeNames; public abstract makeInferred(): TypeNames; public abstract singularize(): TypeNames; @@ -130,7 +147,7 @@ export class RegularTypeNames extends TypeNames { public constructor( public readonly names: ReadonlySet, private readonly _alternativeNames: ReadonlySet | undefined, - distance: number + distance: number, ) { super(distance); } @@ -138,12 +155,18 @@ export class RegularTypeNames extends 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)); + let newAlternativeNames = definedMap( + this._alternativeNames, + (s) => new Set(s), + ); for (let i = startIndex; i < namesArray.length; i++) { const other = namesArray[i]; - if (other instanceof RegularTypeNames && other._alternativeNames !== undefined) { + if ( + other instanceof RegularTypeNames && + other._alternativeNames !== undefined + ) { if (newAlternativeNames === undefined) { newAlternativeNames = new Set(); } @@ -154,7 +177,10 @@ export class RegularTypeNames extends TypeNames { if (other.distance > newDistance) continue; if (!(other instanceof RegularTypeNames)) { - assert(other instanceof TooManyTypeNames, "Unknown TypeNames instance"); + assert( + other instanceof TooManyTypeNames, + "Unknown TypeNames instance", + ); // The other one is at most our distance, so let it sort it out return other.add(namesArray, i + 1); } @@ -163,15 +189,25 @@ export class RegularTypeNames extends TypeNames { // The other one is closer, so take its names newNames = new Set(other.names); newDistance = other.distance; - newAlternativeNames = definedMap(other._alternativeNames, s => new Set(s)); + newAlternativeNames = definedMap( + other._alternativeNames, + (s) => new Set(s), + ); } else { // Same distance, merge them - assert(other.distance === newDistance, "This should be the only case left"); + assert( + other.distance === newDistance, + "This should be the only case left", + ); setUnionInto(newNames, other.names); } } - return TypeNames.makeWithDistance(newNames, newAlternativeNames, newDistance); + return TypeNames.makeWithDistance( + newNames, + newAlternativeNames, + newDistance, + ); } public clearInferred(): TypeNames { @@ -194,19 +230,27 @@ export class RegularTypeNames extends TypeNames { } public makeInferred(): TypeNames { - return TypeNames.makeWithDistance(this.names, this._alternativeNames, this.distance + 1); + return TypeNames.makeWithDistance( + this.names, + this._alternativeNames, + this.distance + 1, + ); } public singularize(): TypeNames { return TypeNames.makeWithDistance( setMap(this.names, pluralize.singular), - definedMap(this._alternativeNames, an => setMap(an, pluralize.singular)), - this.distance + 1 + definedMap(this._alternativeNames, (an) => + setMap(an, pluralize.singular), + ), + this.distance + 1, ); } public toString(): string { - const inferred = this.areInferred ? `distance ${this.distance}` : "given"; + const inferred = this.areInferred + ? `distance ${this.distance}` + : "given"; const names = `${inferred} ${Array.from(this.names).join(",")}`; if (this._alternativeNames === undefined) { return names; @@ -259,7 +303,10 @@ export class TooManyTypeNames extends TypeNames { } public makeInferred(): TypeNames { - return new TooManyTypeNames(this.distance + 1, iterableFirst(this.names)); + return new TooManyTypeNames( + this.distance + 1, + iterableFirst(this.names), + ); } public singularize(): TypeNames { @@ -295,26 +342,36 @@ class TypeNamesTypeAttributeKind extends TypeAttributeKind { } } -export const namesTypeAttributeKind: TypeAttributeKind = new TypeNamesTypeAttributeKind(); +export const namesTypeAttributeKind: TypeAttributeKind = + new TypeNamesTypeAttributeKind(); 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 { - return modifyTypeNames(attributes, maybeNames => { +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)); + typeNames = TypeNames.make( + new Set([nameOrNames]), + new Set(), + defined(areNamesInferred), + ); } else { typeNames = nameOrNames as TypeNames; } diff --git a/packages/quicktype-core/src/attributes/URIAttributes.ts b/packages/quicktype-core/src/attributes/URIAttributes.ts index 2e51278c..29c6f917 100644 --- a/packages/quicktype-core/src/attributes/URIAttributes.ts +++ b/packages/quicktype-core/src/attributes/URIAttributes.ts @@ -1,12 +1,20 @@ import { setUnionManyInto } from "collection-utils"; import URI from "urijs"; -import { type JSONSchemaAttributes, type JSONSchemaType, type Ref } from "../input/JSONSchemaInput"; -import { type JSONSchema } from "../input/JSONSchemaStore"; +import type { + JSONSchemaAttributes, + JSONSchemaType, + Ref, +} from "../input/JSONSchemaInput"; +import type { JSONSchema } from "../input/JSONSchemaStore"; import { checkArray, checkString } from "../support/Support"; -import { type Type } from "../Type/Type"; +import type { Type } from "../Type/Type"; -import { TypeAttributeKind, type TypeAttributes, emptyTypeAttributes } from "./TypeAttributes"; +import { + TypeAttributeKind, + type TypeAttributes, + emptyTypeAttributes, +} from "./TypeAttributes"; const protocolsSchemaProperty = "qt-uri-protocols"; const extensionsSchemaProperty = "qt-uri-extensions"; @@ -24,16 +32,23 @@ class URITypeAttributeKind extends TypeAttributeKind { } 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)]; + const protocolSets = attrs.map((a) => a[0]); + const extensionSets = attrs.map((a) => a[1]); + return [ + setUnionManyInto(new Set(), protocolSets), + setUnionManyInto(new Set(), extensionSets), + ]; } public makeInferred(_: URIAttributes): undefined { return undefined; } - public 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; @@ -47,7 +62,8 @@ class URITypeAttributeKind extends TypeAttributeKind { } } -export const uriTypeAttributeKind: TypeAttributeKind = new URITypeAttributeKind(); +export const uriTypeAttributeKind: TypeAttributeKind = + new URITypeAttributeKind(); const extensionRegex = /^.+(\.[^./\\]+)$/; @@ -61,8 +77,12 @@ export function uriInferenceAttributesProducer(s: string): TypeAttributes { try { const uri = URI(s); const extension = pathExtension(uri.path()); - const extensions = extension === undefined ? [] : [extension.toLowerCase()]; - return uriTypeAttributeKind.makeAttributes([new Set([uri.protocol().toLowerCase()]), new Set(extensions)]); + const extensions = + extension === undefined ? [] : [extension.toLowerCase()]; + return uriTypeAttributeKind.makeAttributes([ + new Set([uri.protocol().toLowerCase()]), + new Set(extensions), + ]); } catch { return emptyTypeAttributes; } @@ -71,7 +91,7 @@ export function uriInferenceAttributesProducer(s: string): TypeAttributes { 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; @@ -94,5 +114,7 @@ export function uriSchemaAttributesProducer( if (protocols.size === 0 && extensions.size === 0) return undefined; - return { forString: uriTypeAttributeKind.makeAttributes([protocols, extensions]) }; + return { + forString: uriTypeAttributeKind.makeAttributes([protocols, extensions]), + }; } diff --git a/packages/quicktype-core/src/index.ts b/packages/quicktype-core/src/index.ts index 4988763b..84005270 100644 --- a/packages/quicktype-core/src/index.ts +++ b/packages/quicktype-core/src/index.ts @@ -5,20 +5,40 @@ export { quicktypeMultiFileSync, quicktype, combineRenderResults, + type RunContext, +} from "./Run"; +export { inferenceFlags, inferenceFlagNames, defaultInferenceFlags, inferenceFlagsObject, type InferenceFlags, type InferenceFlagName, - type RunContext -} from "./Run"; +} from "./Inference"; 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 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 { + Option, + type OptionDefinition, + getOptionValues, + type OptionValues, +} from "./RendererOptions"; export { TargetLanguage, type MultiFileRenderResult } from "./TargetLanguage"; export { @@ -28,7 +48,7 @@ export { type Annotation, modifySource, singleWord, - parenIfNeeded + parenIfNeeded, } from "./Source"; export { Name, funPrefixNamer, Namer } from "./Naming"; export { IssueAnnotationData } from "./Annotation"; @@ -40,7 +60,7 @@ export { parseJSON, checkStringMap, checkArray, - inflateBase64 + inflateBase64, } from "./support/Support"; export { splitIntoWords, @@ -49,7 +69,7 @@ export { firstUpperWordStyle, allUpperWordStyle, legalizeCharacters, - isLetterOrDigit + isLetterOrDigit, } from "./support/Strings"; export { train as trainMarkovChain } from "./MarkovChain"; export { QuickTypeError, messageError, messageAssert } from "./Messages"; @@ -65,7 +85,7 @@ export { ObjectType, type TypeKind, type TransformedStringTypeKind, - type PrimitiveStringTypeKind + type PrimitiveStringTypeKind, } from "./Type"; export { getStream } from "./input/io/get-stream"; @@ -75,12 +95,24 @@ export { FetchingJSONSchemaStore } from "./input/FetchingJSONSchemaStore"; export { JSONSchemaStore, type JSONSchema } from "./input/JSONSchemaStore"; export { sourcesFromPostmanCollection } from "./input/PostmanCollection"; export { TypeBuilder } from "./Type/TypeBuilder"; -export { type StringTypeMapping } from "./Type/TypeBuilderUtils"; +export type { StringTypeMapping } from "./Type/TypeBuilderUtils"; export { type TypeRef, derefTypeRef } from "./Type/TypeRef"; -export { TypeAttributeKind, type TypeAttributes, emptyTypeAttributes } from "./attributes/TypeAttributes"; -export { TypeNames, makeNamesTypeAttributes, namesTypeAttributeKind } from "./attributes/TypeNames"; +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 "./Type/TypeUtils"; +export { + removeNullFromUnion, + matchType, + nullableFromUnion, +} from "./Type/TypeUtils"; export { ConvenienceRenderer } from "./ConvenienceRenderer"; export { uriTypeAttributeKind } from "./attributes/URIAttributes"; diff --git a/packages/quicktype-core/src/input/CompressedJSON.ts b/packages/quicktype-core/src/input/CompressedJSON.ts index 15e6122d..40f9d9a4 100644 --- a/packages/quicktype-core/src/input/CompressedJSON.ts +++ b/packages/quicktype-core/src/input/CompressedJSON.ts @@ -1,12 +1,12 @@ import { addHashCode, hashCodeInit, hashString } from "collection-utils"; import { inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; -import { type DateTimeRecognizer } from "../DateTime"; +import type { DateTimeRecognizer } from "../DateTime"; import { assert, defined, panic } from "../support/Support"; import { type TransformedStringTypeKind, isPrimitiveStringTypeKind, - transformedStringTypeTargetTypeKindsMap + transformedStringTypeTargetTypeKindsMap, } from "../Type"; export enum Tag { @@ -20,7 +20,7 @@ export enum Tag { Object = 8, Array = 9, StringFormat = 10, - TransformedString = 11 + TransformedString = 11, } export type Value = number; @@ -33,7 +33,10 @@ export function makeValue(t: Tag, index: number): Value { } function getIndex(v: Value, tag: Tag): number { - assert(valueTag(v) === tag, "Trying to get index for value with invalid tag"); + assert( + valueTag(v) === tag, + "Trying to get index for value with invalid tag", + ); return v >> TAG_BITS; } @@ -65,7 +68,7 @@ export abstract class CompressedJSON { public constructor( public readonly dateTimeRecognizer: DateTimeRecognizer, - public readonly handleRefs: boolean + public readonly handleRefs: boolean, ) {} public abstract parse(input: T): Promise; @@ -114,7 +117,10 @@ export abstract class CompressedJSON { 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}`); + assert( + typeof value === "number", + `Interned string value is not a number: ${value}`, + ); return value; } @@ -135,19 +141,27 @@ export abstract class CompressedJSON { } protected commitValue(value: Value): void { - assert(typeof value === "number", `CompressedJSON value is not a number: ${value}`); + 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"); + return panic( + "Must have key and can't have string when committing", + ); } - this._ctx.currentObject.push(this.makeString(this._ctx.currentKey), value); + this._ctx.currentObject.push( + this.makeString(this._ctx.currentKey), + value, + ); this._ctx.currentKey = undefined; } else if (this._ctx.currentArray !== undefined) { this._ctx.currentArray.push(value); @@ -174,12 +188,24 @@ export abstract class CompressedJSON { if (this.handleRefs && this.isExpectingRef) { value = this.makeString(s); } else { - const format = inferTransformedStringTypeKindForString(s, this.dateTimeRecognizer); + const format = inferTransformedStringTypeKindForString( + s, + this.dateTimeRecognizer, + ); if (format !== undefined) { - if (defined(transformedStringTypeTargetTypeKindsMap.get(format)).attributesProducer !== undefined) { - value = makeValue(Tag.TransformedString, this.internString(s)); + if ( + defined(transformedStringTypeTargetTypeKindsMap.get(format)) + .attributesProducer !== undefined + ) { + value = makeValue( + Tag.TransformedString, + this.internString(s), + ); } else { - value = makeValue(Tag.StringFormat, this.internString(format)); + value = makeValue( + Tag.StringFormat, + this.internString(format), + ); } } else if (s.length <= 64) { value = this.makeString(s); @@ -197,7 +223,10 @@ export abstract class CompressedJSON { return panic("Finished without root document"); } - assert(this._ctx === undefined && this._contextStack.length === 0, "Finished with contexts present"); + assert( + this._ctx === undefined && this._contextStack.length === 0, + "Finished with contexts present", + ); this._rootValue = undefined; return value; } @@ -211,7 +240,7 @@ export abstract class CompressedJSON { currentObject: undefined, currentArray: undefined, currentKey: undefined, - currentNumberIsDouble: false + currentNumberIsDouble: false, }; } @@ -265,9 +294,14 @@ export abstract class CompressedJSON { hashAccumulator = addHashCode(hashAccumulator, hashString(s)); } - for (const s of Object.getOwnPropertyNames(this._stringIndexes).sort()) { + for (const s of Object.getOwnPropertyNames( + this._stringIndexes, + ).sort()) { hashAccumulator = addHashCode(hashAccumulator, hashString(s)); - hashAccumulator = addHashCode(hashAccumulator, this._stringIndexes[s]); + hashAccumulator = addHashCode( + hashAccumulator, + this._stringIndexes[s], + ); } for (const o of this._objects) { @@ -306,7 +340,9 @@ export class CompressedJSONFromString extends CompressedJSON { this.commitString(json); } else if (typeof json === "number") { const isDouble = - json !== Math.floor(json) || json < Number.MIN_SAFE_INTEGER || json > Number.MAX_SAFE_INTEGER; + json !== Math.floor(json) || + json < Number.MIN_SAFE_INTEGER || + json > Number.MAX_SAFE_INTEGER; this.commitNumber(isDouble); } else if (Array.isArray(json)) { this.pushArrayContext(); diff --git a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts index 028c73d1..ab0c6afa 100644 --- a/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/FetchingJSONSchemaStore.ts @@ -10,6 +10,10 @@ export class FetchingJSONSchemaStore extends JSONSchemaStore { public async fetch(address: string): Promise { // console.log(`Fetching ${address}`); - return parseJSON(await readFromFileOrURL(address, this._httpHeaders), "JSON Schema", 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 ca08b57d..4c315462 100644 --- a/packages/quicktype-core/src/input/Inference.ts +++ b/packages/quicktype-core/src/input/Inference.ts @@ -1,5 +1,11 @@ -import { StringTypes, inferTransformedStringTypeKindForString } from "../attributes/StringTypes"; -import { type TypeAttributes, emptyTypeAttributes } from "../attributes/TypeAttributes"; +import { + StringTypes, + inferTransformedStringTypeKindForString, +} from "../attributes/StringTypes"; +import { + type TypeAttributes, + emptyTypeAttributes, +} from "../attributes/TypeAttributes"; import { messageError } from "../Messages"; import { assert, assertNever, defined, panic } from "../support/Support"; import { @@ -8,14 +14,19 @@ import { ClassType, MapType, UnionType, - transformedStringTypeTargetTypeKindsMap + transformedStringTypeTargetTypeKindsMap, } from "../Type"; -import { type TypeBuilder } from "../Type/TypeBuilder"; +import type { TypeBuilder } from "../Type/TypeBuilder"; import { type TypeRef, derefTypeRef } from "../Type/TypeRef"; import { nullableFromUnion } from "../Type/TypeUtils"; import { UnionAccumulator, UnionBuilder } from "../UnionBuilder"; -import { type CompressedJSON, Tag, type Value, valueTag } from "./CompressedJSON"; +import { + type CompressedJSON, + Tag, + type Value, + valueTag, +} from "./CompressedJSON"; // This should be the recursive type // Value[] | NestedValueArray[] @@ -24,7 +35,10 @@ import { type CompressedJSON, Tag, type Value, valueTag } from "./CompressedJSON // eslint-disable-next-line @typescript-eslint/no-explicit-any 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; } @@ -38,19 +52,26 @@ function forEachArrayInNestedValueArray(va: NestedValueArray, f: (va: Value[]) = } } -function forEachValueInNestedValueArray(va: NestedValueArray, f: (v: Value) => void): void { - forEachArrayInNestedValueArray(va, a => { +function forEachValueInNestedValueArray( + va: NestedValueArray, + f: (v: Value) => void, +): void { + forEachArrayInNestedValueArray(va, (a) => { for (const x of a) { f(x); } }); } -class InferenceUnionBuilder extends UnionBuilder { +class InferenceUnionBuilder extends UnionBuilder< + TypeBuilder, + NestedValueArray, + NestedValueArray +> { public constructor( typeBuilder: TypeBuilder, private readonly _typeInference: TypeInference, - private readonly _fixed: boolean + private readonly _fixed: boolean, ) { super(typeBuilder); } @@ -58,19 +79,29 @@ class InferenceUnionBuilder extends UnionBuilder, private readonly _typeBuilder: TypeBuilder, private readonly _inferMaps: boolean, - private readonly _inferEnums: boolean + private readonly _inferEnums: boolean, ) {} - private addValuesToAccumulator(valueArray: NestedValueArray, accumulator: Accumulator): void { - forEachValueInNestedValueArray(valueArray, value => { + private addValuesToAccumulator( + valueArray: NestedValueArray, + accumulator: Accumulator, + ): void { + forEachValueInNestedValueArray(valueArray, (value) => { const t = valueTag(value); switch (t) { case Tag.Null: @@ -112,12 +146,22 @@ export class TypeInference { if (this._inferEnums) { const s = this._cjson.getStringForValue(value); if (canBeEnumCase(s)) { - accumulator.addStringCase(s, 1, emptyTypeAttributes); + accumulator.addStringCase( + s, + 1, + emptyTypeAttributes, + ); } else { - accumulator.addStringType("string", emptyTypeAttributes); + accumulator.addStringType( + "string", + emptyTypeAttributes, + ); } } else { - accumulator.addStringType("string", emptyTypeAttributes); + accumulator.addStringType( + "string", + emptyTypeAttributes, + ); } break; @@ -125,34 +169,51 @@ export class TypeInference { accumulator.addStringType("string", emptyTypeAttributes); break; case Tag.Object: - accumulator.addObject(this._cjson.getObjectForValue(value), emptyTypeAttributes); + accumulator.addObject( + this._cjson.getObjectForValue(value), + emptyTypeAttributes, + ); break; case Tag.Array: - accumulator.addArray(this._cjson.getArrayForValue(value), emptyTypeAttributes); + accumulator.addArray( + this._cjson.getArrayForValue(value), + emptyTypeAttributes, + ); break; case Tag.StringFormat: { const kind = this._cjson.getStringFormatTypeKind(value); 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); + 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; + const producer = defined( + transformedStringTypeTargetTypeKindsMap.get(kind), + ).attributesProducer; if (producer === undefined) { - return panic("TransformedString does not have attribute producer"); + return panic( + "TransformedString does not have attribute producer", + ); } - accumulator.addStringType("string", producer(s), new StringTypes(new Map(), new Set([kind]))); + accumulator.addStringType( + "string", + producer(s), + new StringTypes(new Map(), new Set([kind])), + ); break; } @@ -166,15 +227,22 @@ export class TypeInference { typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { const accumulator = this.accumulatorForArray(valueArray); - return this.makeTypeFromAccumulator(accumulator, typeAttributes, fixed, forwardingRef); + return this.makeTypeFromAccumulator( + accumulator, + typeAttributes, + fixed, + forwardingRef, + ); } private resolveRef(ref: string, topLevel: TypeRef): TypeRef { if (!ref.startsWith("#/")) { - return messageError("InferenceJSONReferenceNotRooted", { reference: ref }); + return messageError("InferenceJSONReferenceNotRooted", { + reference: ref, + }); } const parts = ref.split("/").slice(1); @@ -186,7 +254,9 @@ export class TypeInference { const nullable = nullableFromUnion(t); if (nullable === null) { // FIXME: handle unions - return messageError("InferenceJSONReferenceToUnion", { reference: ref }); + return messageError("InferenceJSONReferenceToUnion", { + reference: ref, + }); } t = nullable; @@ -195,7 +265,9 @@ export class TypeInference { if (t instanceof ClassType) { const cp = t.getProperties().get(part); if (cp === undefined) { - return messageError("InferenceJSONReferenceWrongProperty", { reference: ref }); + return messageError("InferenceJSONReferenceWrongProperty", { + reference: ref, + }); } tref = cp.typeRef; @@ -203,20 +275,32 @@ export class TypeInference { tref = t.values.typeRef; } else if (t instanceof ArrayType) { if (/^[0-9]+$/.exec(part) === null) { - return messageError("InferenceJSONReferenceInvalidArrayIndex", { reference: ref }); + return messageError( + "InferenceJSONReferenceInvalidArrayIndex", + { reference: ref }, + ); } tref = t.items.typeRef; } else { - return messageError("InferenceJSONReferenceWrongProperty", { reference: ref }); + return messageError("InferenceJSONReferenceWrongProperty", { + reference: ref, + }); } } return tref; } - public inferTopLevelType(typeAttributes: TypeAttributes, valueArray: NestedValueArray, fixed: boolean): TypeRef { - assert(this._refIntersections === undefined, "Didn't reset ref intersections - nested invocations?"); + 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 = []; } @@ -224,8 +308,11 @@ export class TypeInference { const topLevel = this.inferType(typeAttributes, valueArray, fixed); if (this._cjson.handleRefs) { for (const [tref, refs] of defined(this._refIntersections)) { - const resolved = refs.map(r => this.resolveRef(r, topLevel)); - this._typeBuilder.setSetOperationMembers(tref, new Set(resolved)); + const resolved = refs.map((r) => this.resolveRef(r, topLevel)); + this._typeBuilder.setSetOperationMembers( + tref, + new Set(resolved), + ); } this._refIntersections = undefined; @@ -235,7 +322,10 @@ export class TypeInference { } private accumulatorForArray(valueArray: NestedValueArray): Accumulator { - const accumulator = new UnionAccumulator(true); + const accumulator = new UnionAccumulator< + NestedValueArray, + NestedValueArray + >(true); this.addValuesToAccumulator(valueArray, accumulator); return accumulator; } @@ -244,26 +334,37 @@ export class TypeInference { 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); + const unionBuilder = new InferenceUnionBuilder( + this._typeBuilder, + this, + fixed, + ); + return unionBuilder.buildUnion( + accumulator, + false, + typeAttributes, + forwardingRef, + ); } public inferClassType( typeAttributes: TypeAttributes, objects: NestedValueArray, fixed: boolean, - forwardingRef?: TypeRef + forwardingRef?: TypeRef, ): TypeRef { const propertyNames: string[] = []; const propertyValues: { [name: string]: Value[] } = {}; - forEachArrayInNestedValueArray(objects, arr => { + forEachArrayInNestedValueArray(objects, (arr) => { for (let i = 0; i < arr.length; i += 2) { const key = this._cjson.getStringForValue(arr[i]); const value = arr[i + 1]; - if (!Object.prototype.hasOwnProperty.call(propertyValues, key)) { + if ( + !Object.prototype.hasOwnProperty.call(propertyValues, key) + ) { propertyNames.push(key); propertyValues[key] = []; } @@ -272,25 +373,45 @@ export class TypeInference { } }); - if (this._cjson.handleRefs && propertyNames.length === 1 && propertyNames[0] === "$ref") { + if ( + this._cjson.handleRefs && + propertyNames.length === 1 && + propertyNames[0] === "$ref" + ) { const values = propertyValues.$ref; - if (values.every(v => valueTag(v) === Tag.InternedString)) { - const allRefs = values.map(v => this._cjson.getStringForValue(v)); + if (values.every((v) => valueTag(v) === Tag.InternedString)) { + const allRefs = values.map((v) => + this._cjson.getStringForValue(v), + ); // FIXME: Add is-ref attribute - const tref = this._typeBuilder.getUniqueIntersectionType(typeAttributes, undefined); + const tref = this._typeBuilder.getUniqueIntersectionType( + typeAttributes, + undefined, + ); defined(this._refIntersections).push([tref, allRefs]); return tref; } } if (this._inferMaps && propertyNames.length > 500) { - const accumulator = new UnionAccumulator(true); + const accumulator = new UnionAccumulator< + NestedValueArray, + NestedValueArray + >(true); for (const key of propertyNames) { this.addValuesToAccumulator(propertyValues[key], accumulator); } - const values = this.makeTypeFromAccumulator(accumulator, emptyTypeAttributes, fixed); - return this._typeBuilder.getMapType(typeAttributes, values, forwardingRef); + const values = this.makeTypeFromAccumulator( + accumulator, + emptyTypeAttributes, + fixed, + ); + return this._typeBuilder.getMapType( + typeAttributes, + values, + forwardingRef, + ); } const properties = new Map(); @@ -298,13 +419,25 @@ export class TypeInference { const values = propertyValues[key]; const t = this.inferType(emptyTypeAttributes, values, false); const isOptional = values.length < objects.length; - properties.set(key, this._typeBuilder.makeClassProperty(t, isOptional)); + properties.set( + key, + this._typeBuilder.makeClassProperty(t, isOptional), + ); } if (fixed) { - return this._typeBuilder.getUniqueClassType(typeAttributes, true, properties, forwardingRef); - } else { - return this._typeBuilder.getClassType(typeAttributes, properties, forwardingRef); + return this._typeBuilder.getUniqueClassType( + typeAttributes, + true, + properties, + forwardingRef, + ); } + + return this._typeBuilder.getClassType( + typeAttributes, + properties, + forwardingRef, + ); } } diff --git a/packages/quicktype-core/src/input/Inputs.ts b/packages/quicktype-core/src/input/Inputs.ts index 64bc71f4..08092433 100644 --- a/packages/quicktype-core/src/input/Inputs.ts +++ b/packages/quicktype-core/src/input/Inputs.ts @@ -1,16 +1,27 @@ -import { arrayMapSync, iterableFind, iterableFirst, iterableSome, setFilterMap, withDefault } from "collection-utils"; +import { + arrayMapSync, + iterableFind, + iterableFirst, + iterableSome, + setFilterMap, + withDefault, +} from "collection-utils"; import { descriptionTypeAttributeKind } from "../attributes/Description"; import { makeNamesTypeAttributes } from "../attributes/TypeNames"; import { languageNamed } from "../language/All"; import { messageError } from "../Messages"; -import { type RunContext } from "../Run"; +import type { RunContext } from "../Run"; import { defined, errorMessage, panic } from "../support/Support"; -import { type TargetLanguage } from "../TargetLanguage"; -import { type TypeBuilder } from "../Type/TypeBuilder"; -import { type LanguageName } from "../types"; +import type { TargetLanguage } from "../TargetLanguage"; +import type { TypeBuilder } from "../Type/TypeBuilder"; +import type { LanguageName } from "../types"; -import { type CompressedJSON, CompressedJSONFromString, type Value } from "./CompressedJSON"; +import { + type CompressedJSON, + CompressedJSONFromString, + type Value, +} from "./CompressedJSON"; import { TypeInference } from "./Inference"; export interface Input { @@ -21,7 +32,7 @@ export interface Input { typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ) => Promise; addTypesSync: ( @@ -29,7 +40,7 @@ export interface Input { typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ) => void; readonly kind: string; @@ -50,11 +61,15 @@ 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), }); } @@ -80,15 +95,21 @@ export class JSONInput implements Input> { } private setDescription(topLevelName: string, description: string): void { - let topLevel = this._topLevels.get(topLevelName); + const topLevel = this._topLevels.get(topLevelName); if (topLevel === undefined) { - return panic("Trying to set description for a top-level that doesn't exist"); + 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) { @@ -100,7 +121,10 @@ export class JSONInput implements Input> { public async addSource(source: JSONSourceData): Promise { const { name, samples, description } = source; try { - const values = await arrayMapSync(samples, async s => await this._compressedJSON.parse(s)); + const values = await arrayMapSync( + samples, + async (s) => await this._compressedJSON.parse(s), + ); this.addSamples(name, values, description); } catch (e) { return messageParseError(name, description, e); @@ -110,10 +134,12 @@ export class JSONInput implements Input> { public addSourceSync(source: JSONSourceData): void { const { name, samples, description } = source; try { - const values = samples.map(s => this._compressedJSON.parseSync(s)); + const values = samples.map((s) => + this._compressedJSON.parseSync(s), + ); this.addSamples(name, values, description); } catch (e) { - return messageParseError(name, description, e); + messageParseError(name, description, e); } } @@ -126,9 +152,15 @@ export class JSONInput implements Input> { typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ): Promise { - this.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); + this.addTypesSync( + ctx, + typeBuilder, + inferMaps, + inferEnums, + fixedTopLevels, + ); } public addTypesSync( @@ -136,15 +168,26 @@ export class JSONInput implements Input> { typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ): void { - const inference = new TypeInference(this._compressedJSON, typeBuilder, inferMaps, inferEnums); + const inference = new TypeInference( + this._compressedJSON, + typeBuilder, + inferMaps, + inferEnums, + ); for (const [name, { samples, description }] of this._topLevels) { - const tref = inference.inferTopLevelType(makeNamesTypeAttributes(name, false), samples, fixedTopLevels); + const tref = inference.inferTopLevelType( + makeNamesTypeAttributes(name, false), + samples, + fixedTopLevels, + ); typeBuilder.addTopLevel(name, tref); if (description !== undefined) { - const attributes = descriptionTypeAttributeKind.makeAttributes(new Set([description])); + const attributes = descriptionTypeAttributeKind.makeAttributes( + new Set([description]), + ); typeBuilder.addAttributes(tref, attributes); } } @@ -154,27 +197,36 @@ export class JSONInput implements Input> { export function jsonInputForTargetLanguage( targetLanguage: LanguageName | TargetLanguage, languages?: TargetLanguage[], - handleJSONRefs = false + handleJSONRefs = false, ): JSONInput { if (typeof targetLanguage === "string") { targetLanguage = defined(languageNamed(targetLanguage, languages)); } - const compressedJSON = new CompressedJSONFromString(targetLanguage.dateTimeRecognizer, handleJSONRefs); + const compressedJSON = new CompressedJSONFromString( + targetLanguage.dateTimeRecognizer, + handleJSONRefs, + ); return new JSONInput(compressedJSON); } export class InputData { // FIXME: Make into a Map, indexed by kind. - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // biome-ignore lint/suspicious/noExplicitAny: private _inputs: Set> = new Set(); public addInput(input: Input): void { this._inputs = this._inputs.add(input); } - private getOrAddInput(kind: string, makeInput: () => Input): Input { - let input: Input | undefined = iterableFind(this._inputs, i => i.kind === kind); + private getOrAddInput( + kind: string, + makeInput: () => Input, + ): Input { + let input: Input | undefined = iterableFind( + this._inputs, + (i) => i.kind === kind, + ); if (input === undefined) { input = makeInput(); this.addInput(input); @@ -183,12 +235,20 @@ export class InputData { return input; } - public 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); } - public 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); } @@ -198,10 +258,16 @@ export class InputData { 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); + await input.addTypes( + ctx, + typeBuilder, + inferMaps, + inferEnums, + fixedTopLevels, + ); } } @@ -210,25 +276,35 @@ export class InputData { typeBuilder: TypeBuilder, inferMaps: boolean, inferEnums: boolean, - fixedTopLevels: boolean + fixedTopLevels: boolean, ): void { for (const input of this._inputs) { - input.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels); + input.addTypesSync( + ctx, + typeBuilder, + inferMaps, + inferEnums, + fixedTopLevels, + ); } } public get needIR(): boolean { - return iterableSome(this._inputs, i => i.needIR); + return iterableSome(this._inputs, (i) => i.needIR); } public get needSchemaProcessing(): boolean { - return iterableSome(this._inputs, i => i.needSchemaProcessing); + return iterableSome(this._inputs, (i) => i.needSchemaProcessing); } public singleStringSchemaSource(): string | undefined { - const schemaStrings = setFilterMap(this._inputs, i => i.singleStringSchemaSource()); + 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 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 eebcb377..6907c0e4 100644 --- a/packages/quicktype-core/src/input/JSONSchemaInput.ts +++ b/packages/quicktype-core/src/input/JSONSchemaInput.ts @@ -5,7 +5,7 @@ import { arrayLast, arrayMapSync, definedMap, - // eslint-disable-next-line @typescript-eslint/no-redeclare + // biome-ignore lint/suspicious/noShadowRestrictedNames: hasOwnProperty, hashCodeOf, hashString, @@ -18,7 +18,7 @@ import { mapMergeInto, mapSortBy, setFilter, - setSubtract + setSubtract, } from "collection-utils"; import URI from "urijs"; @@ -26,7 +26,7 @@ import { accessorNamesAttributeProducer } from "../attributes/AccessorNames"; import { minMaxAttributeProducer, minMaxLengthAttributeProducer, - patternAttributeProducer + patternAttributeProducer, } from "../attributes/Constraints"; import { descriptionAttributeProducer } from "../attributes/Description"; import { enumValuesAttributeProducer } from "../attributes/EnumValues"; @@ -35,23 +35,35 @@ import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes, - makeTypeAttributesInferred + makeTypeAttributesInferred, } from "../attributes/TypeAttributes"; -import { TypeNames, makeNamesTypeAttributes, modifyTypeNames, singularizeTypeNames } from "../attributes/TypeNames"; +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 { RunContext } from "../Run"; +import { + type StringMap, + assert, + assertNever, + defined, + panic, + parseJSON, +} from "../support/Support"; import { type PrimitiveTypeKind, type TransformedStringTypeKind, isNumberTypeKind, - transformedStringTypeTargetTypeKindsMap + transformedStringTypeTargetTypeKindsMap, } from "../Type"; -import { type TypeBuilder } from "../Type/TypeBuilder"; -import { type TypeRef } from "../Type/TypeRef"; +import type { TypeBuilder } from "../Type/TypeBuilder"; +import type { TypeRef } from "../Type/TypeRef"; -import { type Input } from "./Inputs"; +import type { Input } from "./Inputs"; import { type JSONSchema, JSONSchemaStore } from "./JSONSchemaStore"; import { type PathElement, PathElementKind } from "./PathElement"; @@ -67,7 +79,10 @@ function pathElementEquals(a: PathElement, b: PathElement): boolean { return a.index === b.index; } - if (a.kind === PathElementKind.KeyOrIndex && b.kind === PathElementKind.KeyOrIndex) { + if ( + a.kind === PathElementKind.KeyOrIndex && + b.kind === PathElementKind.KeyOrIndex + ) { return a.key === b.key; } @@ -75,14 +90,27 @@ 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): unknown { +function withRef( + refOrLoc: Ref | (() => Ref) | Location, + props?: T, +): T & { ref: Ref }; +function withRef( + refOrLoc: Ref | (() => Ref) | Location, + props?: T, +): unknown { const ref = - typeof refOrLoc === "function" ? refOrLoc() : refOrLoc instanceof Ref ? refOrLoc : refOrLoc.canonicalRef; + typeof refOrLoc === "function" + ? refOrLoc() + : refOrLoc instanceof Ref + ? refOrLoc + : refOrLoc.canonicalRef; return Object.assign({ ref }, props ?? {}); } -function checkJSONSchemaObject(x: unknown, refOrLoc: Ref | (() => Ref)): StringMap { +function checkJSONSchemaObject( + x: unknown, + refOrLoc: Ref | (() => Ref), +): StringMap { if (Array.isArray(x)) { return messageError("SchemaArrayIsInvalidSchema", withRef(refOrLoc)); } @@ -92,7 +120,10 @@ function checkJSONSchemaObject(x: unknown, refOrLoc: Ref | (() => Ref)): StringM } if (typeof x !== "object") { - return messageError("SchemaInvalidJSONSchemaType", withRef(refOrLoc, { type: typeof x })); + return messageError( + "SchemaInvalidJSONSchemaType", + withRef(refOrLoc, { type: typeof x }), + ); } return x; @@ -103,7 +134,7 @@ function checkJSONSchema(x: unknown, refOrLoc: Ref | (() => Ref)): JSONSchema { return checkJSONSchemaObject(x, refOrLoc); } -const numberRegexp = new RegExp("^[0-9]+$"); +const numberRegexp = /^[0-9]+$/; function normalizeURI(uri: string | URI): URI { // FIXME: This is overly complicated and a bit shady. The problem is @@ -120,7 +151,7 @@ function normalizeURI(uri: string | URI): URI { export class Ref { public static root(address: string | undefined): Ref { - const uri = definedMap(address, a => new URI(a)); + const uri = definedMap(address, (a) => new URI(a)); return new Ref(uri, []); } @@ -134,7 +165,9 @@ export class Ref { if (path !== "") { const parts = path.split("/"); - parts.forEach(part => elements.push({ kind: PathElementKind.KeyOrIndex, key: part })); + parts.forEach((part) => + elements.push({ kind: PathElementKind.KeyOrIndex, key: part }), + ); } return elements; @@ -163,10 +196,13 @@ export class Ref { public constructor( addressURI: URI | undefined, - public readonly path: readonly PathElement[] + public readonly path: readonly PathElement[], ) { if (addressURI !== undefined) { - assert(addressURI.fragment() === "", `Ref URI with fragment is not allowed: ${addressURI.toString()}`); + assert( + addressURI.fragment() === "", + `Ref URI with fragment is not allowed: ${addressURI.toString()}`, + ); this.addressURI = normalizeURI(addressURI); } else { this.addressURI = undefined; @@ -182,7 +218,9 @@ export class Ref { } public get isRoot(): boolean { - return this.path.length === 1 && this.path[0].kind === PathElementKind.Root; + return ( + this.path.length === 1 && this.path[0].kind === PathElementKind.Root + ); } private pushElement(pe: PathElement): Ref { @@ -212,7 +250,10 @@ export class Ref { public resolveAgainst(base: Ref | undefined): Ref { let addressURI = this.addressURI; if (base?.addressURI !== undefined) { - addressURI = addressURI === undefined ? base.addressURI : addressURI.absoluteTo(base.addressURI); + addressURI = + addressURI === undefined + ? base.addressURI + : addressURI.absoluteTo(base.addressURI); } return new Ref(addressURI, this.path); @@ -224,8 +265,14 @@ export class Ref { for (;;) { const e = path.pop(); if (e === undefined || e.kind === PathElementKind.Root) { - let name = this.addressURI !== undefined ? this.addressURI.filename() : ""; - const suffix = this.addressURI !== undefined ? this.addressURI.suffix() : ""; + let name = + this.addressURI !== undefined + ? this.addressURI.filename() + : ""; + const suffix = + this.addressURI !== undefined + ? this.addressURI.suffix() + : ""; if (name.length > suffix.length + 1) { name = name.slice(0, name.length - suffix.length - 1); } @@ -246,7 +293,9 @@ export class Ref { break; case PathElementKind.Type: case PathElementKind.Object: - return panic("We shouldn't try to get the name of Type or Object refs"); + return panic( + "We shouldn't try to get the name of Type or Object refs", + ); default: return assertNever(e); } @@ -256,7 +305,8 @@ export class Ref { 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))); + if (keyOrIndex(pe) === "definitions") + return keyOrIndex(defined(arrayLast(this.path))); return undefined; } @@ -276,11 +326,16 @@ export class Ref { } } - const address = this.addressURI === undefined ? "" : this.addressURI.toString(); - return address + "#" + this.path.map(elementToString).join("/"); + const address = + this.addressURI === undefined ? "" : this.addressURI.toString(); + return `${address}#${this.path.map(elementToString).join("/")}`; } - private lookup(local: unknown, path: readonly PathElement[], root: JSONSchema): JSONSchema { + private lookup( + local: unknown, + path: readonly PathElement[], + root: JSONSchema, + ): JSONSchema { const refMaker = (): Ref => new Ref(this.addressURI, path); const first = path[0]; if (first === undefined) { @@ -295,23 +350,36 @@ export class Ref { const key = first.key; if (Array.isArray(local)) { if (!/^\d+$/.test(key)) { - return messageError("SchemaCannotIndexArrayWithNonNumber", withRef(refMaker, { actual: key })); + return messageError( + "SchemaCannotIndexArrayWithNonNumber", + withRef(refMaker, { actual: key }), + ); } - const index = parseInt(first.key, 10); + const index = Number.parseInt(first.key, 10); if (index >= local.length) { - return messageError("SchemaIndexNotInArray", withRef(refMaker, { index })); + 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); } + 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"'); case PathElementKind.Object: @@ -330,7 +398,11 @@ export class Ref { 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; @@ -343,7 +415,7 @@ export class Ref { } public hashCode(): number { - let acc = hashCodeOf(definedMap(this.addressURI, u => u.toString())); + let acc = hashCodeOf(definedMap(this.addressURI, (u) => u.toString())); for (const pe of this.path) { acc = addHashCode(acc, pe.kind); switch (pe.kind) { @@ -370,7 +442,7 @@ class Location { public constructor( canonicalRef: Ref, virtualRef?: Ref, - public readonly haveID: boolean = false + public readonly haveID: boolean = false, ) { this.canonicalRef = canonicalRef; this.virtualRef = virtualRef ?? canonicalRef; @@ -379,24 +451,42 @@ class Location { 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; + const virtual = this.haveID + ? parsed.resolveAgainst(this.virtualRef) + : parsed; if (!this.haveID) { - messageAssert(virtual.hasAddress, "SchemaIDMustHaveAddress", withRef(this, { id })); + messageAssert( + virtual.hasAddress, + "SchemaIDMustHaveAddress", + withRef(this, { id }), + ); } return new Location(this.canonicalRef, virtual, true); } public push(...keys: string[]): Location { - return new Location(this.canonicalRef.push(...keys), this.virtualRef.push(...keys), this.haveID); + return new Location( + this.canonicalRef.push(...keys), + this.virtualRef.push(...keys), + this.haveID, + ); } public pushObject(): Location { - return new Location(this.canonicalRef.pushObject(), this.virtualRef.pushObject(), this.haveID); + return new Location( + this.canonicalRef.pushObject(), + this.virtualRef.pushObject(), + this.haveID, + ); } public pushType(index: number): Location { - return new Location(this.canonicalRef.pushType(index), this.virtualRef.pushType(index), this.haveID); + return new Location( + this.canonicalRef.pushType(index), + this.virtualRef.pushType(index), + this.haveID, + ); } public toString(): string { @@ -440,14 +530,20 @@ class Canonizer { } for (const property of Object.getOwnPropertyNames(schema)) { - this.addIDs(schema[property as keyof typeof schema], loc.push(property)); + this.addIDs( + schema[property as keyof typeof schema], + loc.push(property), + ); } } 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))); + this.addIDs( + schema, + new Location(Ref.root(address), Ref.root(undefined)), + ); this._schemaAddressesAdded.add(address); return true; } @@ -461,12 +557,17 @@ class Canonizer { } const canonicalRef = - virtual.addressURI === undefined ? new Ref(base.canonicalRef.addressURI, virtual.path) : virtual; + virtual.addressURI === undefined + ? new Ref(base.canonicalRef.addressURI, virtual.path) + : virtual; return new Location(canonicalRef, new Ref(undefined, virtual.path)); } } -function checkTypeList(typeOrTypes: string | string[], loc: Location): ReadonlySet { +function checkTypeList( + typeOrTypes: string | string[], + loc: Location, +): ReadonlySet { let set: Set; if (typeof typeOrTypes === "string") { set = new Set([typeOrTypes]); @@ -474,7 +575,10 @@ function checkTypeList(typeOrTypes: string | string[], loc: Location): ReadonlyS const arr: string[] = []; for (const t of typeOrTypes) { if (typeof t !== "string") { - return messageError("SchemaTypeElementMustBeString", withRef(loc, { element: t })); + return messageError( + "SchemaTypeElementMustBeString", + withRef(loc, { element: t }), + ); } arr.push(t); @@ -482,14 +586,28 @@ function checkTypeList(typeOrTypes: string | string[], loc: Location): ReadonlyS set = new Set(arr); } else { - return messageError("SchemaTypeMustBeStringOrStringArray", withRef(loc, { actual: typeOrTypes })); + 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.includes(s)); + const validTypes = [ + "null", + "boolean", + "object", + "array", + "number", + "string", + "integer", + ]; + const maybeInvalid = iterableFind(set, (s) => !validTypes.includes(s)); if (maybeInvalid !== undefined) { - return messageError("SchemaInvalidType", withRef(loc, { type: maybeInvalid })); + return messageError( + "SchemaInvalidType", + withRef(loc, { type: maybeInvalid }), + ); } return set; @@ -497,12 +615,18 @@ function checkTypeList(typeOrTypes: string | string[], loc: Location): ReadonlyS function checkRequiredArray(arr: string[], loc: Location): string[] { if (!Array.isArray(arr)) { - return messageError("SchemaRequiredMustBeStringOrStringArray", withRef(loc, { actual: 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 messageError( + "SchemaRequiredElementMustBeString", + withRef(loc, { element: e }), + ); } } @@ -516,11 +640,13 @@ 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[]; +const schemaTypes = Object.getOwnPropertyNames( + schemaTypeDict, +) as JSONSchemaType[]; export interface JSONSchemaAttributes { forCases?: TypeAttributes[]; @@ -534,13 +660,15 @@ export type JSONSchemaAttributeProducer = ( schema: JSONSchema, canonicalRef: Ref, types: Set, - unionCases: JSONSchema[] | undefined + 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; @@ -549,22 +677,25 @@ function typeKindForJSONSchemaFormat(format: string): TransformedStringTypeKind function schemaFetchError(base: Location | undefined, address: string): never { if (base === undefined) { return messageError("SchemaFetchErrorTopLevel", { address }); - } else { - return messageError("SchemaFetchError", { address, base: base.canonicalRef }); } + + return messageError("SchemaFetchError", { + address, + base: base.canonicalRef, + }); } class Resolver { public constructor( private readonly _ctx: RunContext, private readonly _store: JSONSchemaStore, - private readonly _canonizer: Canonizer + private readonly _canonizer: Canonizer, ) {} 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 @@ -574,13 +705,19 @@ class Resolver { for (;;) { const loc = this._canonizer.canonize(fetchBase, virtualRef); const canonical = loc.canonicalRef; - assert(canonical.hasAddress, "Canonical ref can't be resolved without an address"); + assert( + canonical.hasAddress, + "Canonical ref can't be resolved without an address", + ); const address = canonical.address; - let schema = + const schema = canonical.addressURI === undefined ? undefined - : await this._store.get(address, this._ctx.debugPrintSchemaResolving); + : await this._store.get( + address, + this._ctx.debugPrintSchemaResolving, + ); if (schema === undefined) { return [undefined, loc]; } @@ -589,12 +726,18 @@ class Resolver { assert(!didAdd, "We can't add a schema twice"); didAdd = true; } else { - let lookupLoc = this._canonizer.canonize(lookupBase, virtualRef); + let lookupLoc = this._canonizer.canonize( + lookupBase, + virtualRef, + ); if (fetchBase !== undefined) { lookupLoc = new Location( - new Ref(loc.canonicalRef.addressURI, lookupLoc.canonicalRef.path), + new Ref( + loc.canonicalRef.addressURI, + lookupLoc.canonicalRef.path, + ), lookupLoc.virtualRef, - lookupLoc.haveID + lookupLoc.haveID, ); } @@ -603,9 +746,14 @@ class Resolver { } } - public 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()}`); + console.log( + `resolving ${virtualRef.toString()} relative to ${base.toString()}`, + ); } // Try with the virtual base first. If that doesn't work, use the @@ -623,7 +771,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]; @@ -639,7 +787,10 @@ class Resolver { } public async resolveTopLevelRef(ref: Ref): Promise<[JSONSchema, Location]> { - return await this.resolveVirtualRef(new Location(new Ref(ref.addressURI, [])), new Ref(undefined, ref.path)); + return await this.resolveVirtualRef( + new Location(new Ref(ref.addressURI, [])), + new Ref(undefined, ref.path), + ); } } @@ -647,14 +798,17 @@ async function addTypesInSchema( resolver: Resolver, typeBuilder: TypeBuilder, references: ReadonlyMap, - attributeProducers: JSONSchemaAttributeProducer[] + attributeProducers: JSONSchemaAttributeProducer[], ): Promise { - let typeForCanonicalRef = new EqualityMap(); + const typeForCanonicalRef = new EqualityMap(); 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"); + assert( + maybeRef === t, + "Trying to set path again to different type", + ); } typeForCanonicalRef.set(loc.canonicalRef, t); @@ -666,31 +820,43 @@ async function addTypesInSchema( properties: StringMap, requiredArray: string[], additionalProperties: unknown, - sortKey: (k: string) => number | string = (k: string): 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)); - const props = await mapMapSync(propertiesMap, async (propSchema, propName) => { - const propLoc = loc.push("properties", propName); - const t = await toType( - checkJSONSchema(propSchema, propLoc.canonicalRef), - propLoc, - makeNamesTypeAttributes(propName, true) - ); - const isOptional = !required.has(propName); - return typeBuilder.makeClassProperty(t, isOptional); - }); + const propertiesMap = mapSortBy(mapFromObject(properties), (_, k) => + sortKey(k), + ); + const props = await mapMapSync( + propertiesMap, + async (propSchema, propName) => { + const propLoc = loc.push("properties", propName); + const t = await toType( + checkJSONSchema(propSchema, propLoc.canonicalRef), + propLoc, + makeNamesTypeAttributes(propName, true), + ); + const isOptional = !required.has(propName); + return typeBuilder.makeClassProperty(t, isOptional); + }, + ); let additionalPropertiesType: TypeRef | undefined; - if (additionalProperties === undefined || additionalProperties === true) { + if ( + additionalProperties === undefined || + additionalProperties === true + ) { additionalPropertiesType = typeBuilder.getPrimitiveType("any"); } else if (additionalProperties === false) { additionalPropertiesType = undefined; } else { const additionalLoc = loc.push("additionalProperties"); additionalPropertiesType = await toType( - checkJSONSchema(additionalProperties, additionalLoc.canonicalRef), + checkJSONSchema( + additionalProperties, + additionalLoc.canonicalRef, + ), additionalLoc, - singularizeTypeNames(attributes) + singularizeTypeNames(attributes), ); } @@ -698,22 +864,34 @@ async function addTypesInSchema( if (additionalRequired.size > 0) { const t = additionalPropertiesType; if (t === undefined) { - return messageError("SchemaAdditionalTypesForbidRequired", withRef(loc)); + return messageError( + "SchemaAdditionalTypesForbidRequired", + withRef(loc), + ); } - const additionalProps = mapFromIterable(additionalRequired, _name => - typeBuilder.makeClassProperty(t, false) + const additionalProps = mapFromIterable( + additionalRequired, + (_name) => typeBuilder.makeClassProperty(t, false), ); mapMergeInto(props, additionalProps); } - return typeBuilder.getUniqueObjectType(attributes, props, additionalPropertiesType); + 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)); + const typeSet = definedMap(schema.type, (t) => checkTypeList(t, loc)); function isTypeIncluded(name: JSONSchemaType): boolean { if (typeSet !== undefined && !typeSet.has(name)) { @@ -727,7 +905,8 @@ async function addTypesInSchema( predicate = (x): x is null => x === null; break; case "integer": - predicate = (x): x is number => typeof x === "number" && x === Math.floor(x); + predicate = (x): x is number => + typeof x === "number" && x === Math.floor(x); break; default: predicate = (x): x is typeof name => typeof x === name; @@ -745,19 +924,28 @@ async function addTypesInSchema( } const includedTypes = setFilter(schemaTypes, isTypeIncluded); - let producedAttributesForNoCases: JSONSchemaAttributes[] | undefined = undefined; + let producedAttributesForNoCases: JSONSchemaAttributes[] | undefined = + undefined; function forEachProducedAttribute( cases: JSONSchema[] | undefined, - f: (attributes: JSONSchemaAttributes) => void + f: (attributes: JSONSchemaAttributes) => void, ): void { let attributes: JSONSchemaAttributes[]; - if (cases === undefined && producedAttributesForNoCases !== undefined) { + if ( + cases === undefined && + producedAttributesForNoCases !== undefined + ) { attributes = producedAttributesForNoCases; } else { attributes = []; for (const producer of attributeProducers) { - const newAttributes = producer(schema, loc.canonicalRef, includedTypes, cases); + const newAttributes = producer( + schema, + loc.canonicalRef, + includedTypes, + cases, + ); if (newAttributes === undefined) continue; attributes.push(newAttributes); } @@ -773,13 +961,17 @@ async function addTypesInSchema( } function combineProducedAttributes( - f: (attributes: JSONSchemaAttributes) => TypeAttributes | undefined + f: (attributes: JSONSchemaAttributes) => TypeAttributes | undefined, ): TypeAttributes { let result = emptyTypeAttributes; - forEachProducedAttribute(undefined, attr => { + forEachProducedAttribute(undefined, (attr) => { const maybeAttributes = f(attr); if (maybeAttributes === undefined) return; - result = combineTypeAttributes("union", result, maybeAttributes); + result = combineTypeAttributes( + "union", + result, + maybeAttributes, + ); }); return result; } @@ -789,17 +981,20 @@ async function addTypesInSchema( attributes = combineTypeAttributes( "union", attributes, - 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" - ); - return forType; - }) + 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", + ); + return forType; + }, + ), ); } - return modifyTypeNames(attributes, maybeTypeNames => { + return modifyTypeNames(attributes, (maybeTypeNames) => { const typeNames = defined(maybeTypeNames); if (!typeNames.areInferred) { return typeNames; @@ -811,10 +1006,14 @@ async function addTypesInSchema( } if (typeof title === "string") { - return TypeNames.make(new Set([title]), new Set(), schema.$ref !== undefined); - } else { - return typeNames.makeInferred(); + return TypeNames.make( + new Set([title]), + new Set(), + schema.$ref !== undefined, + ); } + + return typeNames.makeInferred(); }); } @@ -824,10 +1023,13 @@ async function addTypesInSchema( function makeStringType(attributes: TypeAttributes): TypeRef { const kind = typeKindForJSONSchemaFormat(schema.format); if (kind === undefined) { - return typeBuilder.getStringType(attributes, StringTypes.unrestricted); - } else { - return typeBuilder.getPrimitiveType(kind, attributes); + return typeBuilder.getStringType( + attributes, + StringTypes.unrestricted, + ); } + + return typeBuilder.getPrimitiveType(kind, attributes); } async function makeArrayType(): Promise { @@ -838,14 +1040,28 @@ async function addTypesInSchema( const itemsLoc = loc.push("items"); const itemTypes = await arrayMapSync(items, async (item, i) => { const itemLoc = itemsLoc.push(i.toString()); - return await toType(checkJSONSchema(item, itemLoc.canonicalRef), itemLoc, singularAttributes); + return await toType( + checkJSONSchema(item, itemLoc.canonicalRef), + itemLoc, + singularAttributes, + ); }); - itemType = typeBuilder.getUnionType(emptyTypeAttributes, new Set(itemTypes)); + itemType = typeBuilder.getUnionType( + emptyTypeAttributes, + new Set(itemTypes), + ); } else if (typeof items === "object") { const itemsLoc = loc.push("items"); - itemType = await toType(checkJSONSchema(items, itemsLoc.canonicalRef), itemsLoc, singularAttributes); + itemType = await toType( + checkJSONSchema(items, itemsLoc.canonicalRef), + itemsLoc, + singularAttributes, + ); } else if (items !== undefined && items !== true) { - return messageError("SchemaArrayItemsMustBeStringOrArray", withRef(loc, { actual: items })); + return messageError( + "SchemaArrayItemsMustBeStringOrArray", + withRef(loc, { actual: items }), + ); } else { itemType = typeBuilder.getPrimitiveType("any"); } @@ -856,7 +1072,10 @@ async function addTypesInSchema( async function makeObjectType(): Promise { let required: string[]; - if (schema.required === undefined || typeof schema.required === "boolean") { + if ( + schema.required === undefined || + typeof schema.required === "boolean" + ) { required = []; } else { required = Array.from(checkRequiredArray(schema.required, loc)); @@ -866,7 +1085,10 @@ async function addTypesInSchema( if (schema.properties === undefined) { properties = {}; } else { - properties = checkJSONSchemaObject(schema.properties, loc.canonicalRef); + properties = checkJSONSchemaObject( + schema.properties, + loc.canonicalRef, + ); } // In Schema Draft 3, `required` is `true` on a property that's required. @@ -890,9 +1112,11 @@ async function addTypesInSchema( const objectAttributes = combineTypeAttributes( "union", inferredAttributes, - combineProducedAttributes(({ forObject }) => forObject) + combineProducedAttributes(({ forObject }) => forObject), ); - const order = schema.quicktypePropertyOrder ? schema.quicktypePropertyOrder : []; + const order = schema.quicktypePropertyOrder + ? schema.quicktypePropertyOrder + : []; const orderKey = (propertyName: string): string => { // use the index of the order array const index = order.indexOf(propertyName); @@ -900,13 +1124,26 @@ async function addTypesInSchema( return index !== -1 ? index : propertyName.toLowerCase(); }; - return await makeObject(loc, objectAttributes, properties, required, additionalProperties, orderKey); + return await makeObject( + loc, + objectAttributes, + properties, + required, + additionalProperties, + orderKey, + ); } - async function makeTypesFromCases(cases: unknown[], 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 })); + return messageError( + "SchemaSetOperationCasesIsNotArray", + withRef(kindLoc, { operation: kind, cases }), + ); } return await arrayMapSync(cases, async (t, index) => { @@ -914,49 +1151,77 @@ async function addTypesInSchema( return await toType( checkJSONSchema(t, caseLoc.canonicalRef), caseLoc, - makeTypeAttributesInferred(typeAttributes) + makeTypeAttributesInferred(typeAttributes), ); }); } - const intersectionType = typeBuilder.getUniqueIntersectionType(typeAttributes, undefined); + const intersectionType = typeBuilder.getUniqueIntersectionType( + typeAttributes, + undefined, + ); setTypeForLocation(loc, intersectionType); - async function convertOneOrAnyOf(cases: unknown[], kind: string): Promise { + async function convertOneOrAnyOf( + cases: unknown[], + kind: string, + ): Promise { const typeRefs = await makeTypesFromCases(cases, kind); let unionAttributes = makeTypeAttributesInferred(typeAttributes); if (kind === "oneOf") { - forEachProducedAttribute(cases as JSONSchema[], ({ forType, forUnion, forCases }) => { - 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" - ); - for (let i = 0; i < typeRefs.length; i++) { - typeBuilder.addAttributes(typeRefs[i], forCases[i]); + forEachProducedAttribute( + cases as JSONSchema[], + ({ forType, forUnion, forCases }) => { + 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", + ); + for (let i = 0; i < typeRefs.length; i++) { + typeBuilder.addAttributes( + typeRefs[i], + forCases[i], + ); + } + } + }, + ); } - const unionType = typeBuilder.getUniqueUnionType(unionAttributes, undefined); + const unionType = typeBuilder.getUniqueUnionType( + unionAttributes, + undefined, + ); typeBuilder.setSetOperationMembers(unionType, new Set(typeRefs)); return unionType; } - const includeObject = enumArray === undefined && !isConst && (typeSet === undefined || typeSet.has("object")); - const includeArray = enumArray === undefined && !isConst && (typeSet === undefined || typeSet.has("array")); + const includeObject = + enumArray === undefined && + !isConst && + (typeSet === undefined || typeSet.has("object")); + const includeArray = + enumArray === undefined && + !isConst && + (typeSet === undefined || typeSet.has("array")); const needStringEnum = includedTypes.has("string") && - enumArray?.find(x => typeof x === "string") !== undefined; + enumArray?.find((x) => typeof x === "string") !== undefined; const needUnion = typeSet !== undefined || schema.properties !== undefined || @@ -971,29 +1236,40 @@ async function addTypesInSchema( if (needUnion) { const unionTypes: TypeRef[] = []; - const numberAttributes = combineProducedAttributes(({ forNumber }) => forNumber); + const numberAttributes = combineProducedAttributes( + ({ forNumber }) => forNumber, + ); for (const [name, kind] of [ ["null", "null"], ["number", "double"], ["integer", "integer"], - ["boolean", "bool"] + ["boolean", "bool"], ] as Array<[JSONSchemaType, PrimitiveTypeKind]>) { if (!includedTypes.has(name)) continue; - const attributes = isNumberTypeKind(kind) ? numberAttributes : undefined; + const attributes = isNumberTypeKind(kind) + ? numberAttributes + : undefined; unionTypes.push(typeBuilder.getPrimitiveType(kind, attributes)); } const stringAttributes = combineTypeAttributes( "union", inferredAttributes, - combineProducedAttributes(({ forString }) => forString) + combineProducedAttributes(({ forString }) => forString), ); if (needStringEnum || isConst) { - const cases = isConst ? [schema.const] : enumArray?.filter(x => typeof x === "string") ?? []; - unionTypes.push(typeBuilder.getStringType(stringAttributes, StringTypes.fromCases(cases))); + 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)); } @@ -1006,19 +1282,34 @@ async function addTypesInSchema( unionTypes.push(await makeObjectType()); } - types.push(typeBuilder.getUniqueUnionType(inferredAttributes, new Set(unionTypes))); + types.push( + typeBuilder.getUniqueUnionType( + inferredAttributes, + new Set(unionTypes), + ), + ); } if (schema.$ref !== undefined) { if (typeof schema.$ref !== "string") { - return messageError("SchemaRefMustBeString", withRef(loc, { actual: typeof schema.$ref })); + 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 => { + const [target, newLoc] = await resolver.resolveVirtualRef( + loc, + virtualRef, + ); + const attributes = modifyTypeNames(typeAttributes, (tn) => { if (!defined(tn).areInferred) return tn; - return TypeNames.make(new Set([newLoc.canonicalRef.name]), new Set(), true); + return TypeNames.make( + new Set([newLoc.canonicalRef.name]), + new Set(), + true, + ); }); types.push(await toType(target, newLoc, attributes)); } @@ -1039,7 +1330,11 @@ 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; @@ -1049,7 +1344,11 @@ async function addTypesInSchema( if (typeof schema === "boolean") { // FIXME: Empty union. We'd have to check that it's supported everywhere, // in particular in union flattening. - messageAssert(schema === true, "SchemaFalseNotSupported", withRef(loc)); + messageAssert( + schema === true, + "SchemaFalseNotSupported", + withRef(loc), + ); result = typeBuilder.getPrimitiveType("any"); } else { loc = loc.updateWithID(schema.$id); @@ -1062,7 +1361,11 @@ async function addTypesInSchema( for (const [topLevelName, topLevelRef] of references) { const [target, loc] = await resolver.resolveTopLevelRef(topLevelRef); - const t = await toType(target, loc, makeNamesTypeAttributes(topLevelName, false)); + const t = await toType( + target, + loc, + makeNamesTypeAttributes(topLevelName, false), + ); typeBuilder.addTopLevel(topLevelName, t); } } @@ -1101,13 +1404,15 @@ function nameFromURI(uri: URI): string | undefined { return removeExtension(filename); } - return messageError("DriverCannotInferNameForSchema", { uri: uri.toString() }); + return messageError("DriverCannotInferNameForSchema", { + uri: uri.toString(), + }); } async function refsInSchemaForURI( resolver: Resolver, uri: URI, - defaultName: string + defaultName: string, ): Promise | [string, Ref]> { const fragment = uri.fragment(); let propertiesAreTypes = fragment.endsWith("/"); @@ -1124,27 +1429,29 @@ async function refsInSchemaForURI( if (propertiesAreTypes) { if (typeof schema !== "object") { - return messageError("SchemaCannotGetTypesFromBoolean", { ref: ref.toString() }); + return messageError("SchemaCannotGetTypesFromBoolean", { + ref: ref.toString(), + }); } return mapMap(mapFromObject(schema), (_, name) => ref.push(name)); - } else { - let name: string; - if (typeof schema === "object" && typeof schema.title === "string") { - name = schema.title; - } else { - const maybeName = nameFromURI(uri); - name = maybeName ?? defaultName; - } - - return [name, ref]; } + + let name: string; + if (typeof schema === "object" && typeof schema.title === "string") { + name = schema.title; + } else { + const maybeName = nameFromURI(uri); + name = maybeName ?? defaultName; + } + + return [name, ref]; } class InputJSONSchemaStore extends JSONSchemaStore { public constructor( private readonly _inputs: Map, - private readonly _delegate?: JSONSchemaStore + private readonly _delegate?: JSONSchemaStore, ) { super(); } @@ -1152,7 +1459,10 @@ class InputJSONSchemaStore extends JSONSchemaStore { 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)); + return checkJSONSchema( + parseJSON(maybeInput, "JSON Schema", address), + () => Ref.root(address), + ); } if (this._delegate === undefined) { @@ -1188,7 +1498,7 @@ export class JSONSchemaInput implements Input { public constructor( private _schemaStore: JSONSchemaStore | undefined, additionalAttributeProducers: JSONSchemaAttributeProducer[] = [], - private readonly _additionalSchemaAddresses: readonly string[] = [] + private readonly _additionalSchemaAddresses: readonly string[] = [], ) { this._attributeProducers = [ descriptionAttributeProducer, @@ -1197,7 +1507,7 @@ export class JSONSchemaInput implements Input { uriSchemaAttributesProducer, minMaxAttributeProducer, minMaxLengthAttributeProducer, - patternAttributeProducer + patternAttributeProducer, ].concat(additionalAttributeProducers); } @@ -1209,7 +1519,10 @@ export class JSONSchemaInput implements Input { this._topLevels.set(name, ref); } - public 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; @@ -1218,14 +1531,20 @@ export class JSONSchemaInput implements Input { return panic("Must have a schema store to process JSON Schema"); } } else { - maybeSchemaStore = this._schemaStore = new InputJSONSchemaStore(this._schemaInputs, maybeSchemaStore); + maybeSchemaStore = this._schemaStore = new InputJSONSchemaStore( + this._schemaInputs, + maybeSchemaStore, + ); } const schemaStore = maybeSchemaStore; const canonizer = new Canonizer(ctx); for (const address of this._additionalSchemaAddresses) { - const schema = await schemaStore.get(address, ctx.debugPrintSchemaResolving); + const schema = await schemaStore.get( + address, + ctx.debugPrintSchemaResolving, + ); if (schema === undefined) { return messageError("SchemaFetchErrorAdditional", { address }); } @@ -1233,15 +1552,26 @@ export class JSONSchemaInput implements Input { canonizer.addSchema(schema, address); } - const resolver = new Resolver(ctx, defined(this._schemaStore), canonizer); + const resolver = new Resolver( + ctx, + defined(this._schemaStore), + canonizer, + ); for (const [normalizedURI, source] of this._schemaSources) { const givenName = source.name; - const refs = await refsInSchemaForURI(resolver, normalizedURI, givenName); + const refs = await refsInSchemaForURI( + resolver, + normalizedURI, + givenName, + ); if (Array.isArray(refs)) { let name: string; - if (this._schemaSources.length === 1 && givenName !== undefined) { + if ( + this._schemaSources.length === 1 && + givenName !== undefined + ) { name = givenName; } else { name = refs[0]; @@ -1255,11 +1585,16 @@ export class JSONSchemaInput implements Input { } } - await addTypesInSchema(resolver, typeBuilder, this._topLevels, this._attributeProducers); + await addTypesInSchema( + resolver, + typeBuilder, + this._topLevels, + this._attributeProducers, + ); } public addTypesSync(): void { - return panic("addTypesSync not supported in JSONSchemaInput"); + panic("addTypesSync not supported in JSONSchemaInput"); } public async addSource(schemaSource: JSONSchemaSourceData): Promise { @@ -1277,7 +1612,7 @@ export class JSONSchemaInput implements Input { if (uris === undefined) { normalizedURIs = [new URI(name)]; } else { - normalizedURIs = uris.map(uri => { + normalizedURIs = uris.map((uri) => { const normalizedURI = normalizeURI(uri); if (normalizedURI.clone().hash("").toString() === "") { normalizedURI.path(name); @@ -1288,7 +1623,10 @@ export class JSONSchemaInput implements Input { } if (schema === undefined) { - assert(uris !== undefined, "URIs must be given if schema source is not specified"); + assert( + uris !== undefined, + "URIs must be given if schema source is not specified", + ); } else { for (let i = 0; i < normalizedURIs.length; i++) { const normalizedURI = normalizedURIs[i]; @@ -1315,11 +1653,17 @@ export class JSONSchemaInput implements Input { } public singleStringSchemaSource(): string | undefined { - if (!this._schemaSources.every(([_, { schema }]) => typeof schema === "string")) { + if ( + !this._schemaSources.every( + ([_, { schema }]) => typeof schema === "string", + ) + ) { return undefined; } - const set = new Set(this._schemaSources.map(([_, { schema }]) => schema as string)); + const set = new Set( + this._schemaSources.map(([_, { schema }]) => schema as string), + ); if (set.size === 1) { return defined(iterableFirst(set)); } diff --git a/packages/quicktype-core/src/input/JSONSchemaStore.ts b/packages/quicktype-core/src/input/JSONSchemaStore.ts index 02d93e8e..d0519e4a 100644 --- a/packages/quicktype-core/src/input/JSONSchemaStore.ts +++ b/packages/quicktype-core/src/input/JSONSchemaStore.ts @@ -6,14 +6,20 @@ export abstract class JSONSchemaStore { private readonly _schemas = new Map(); private add(address: string, schema: JSONSchema): void { - assert(!this._schemas.has(address), "Cannot set a schema for an address twice"); + assert( + !this._schemas.has(address), + "Cannot set a schema for an address twice", + ); this._schemas.set(address, schema); } // FIXME: Remove the undefined option public abstract fetch(_address: string): Promise; - public 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/input/PathElement.ts b/packages/quicktype-core/src/input/PathElement.ts index eba390d7..44048453 100644 --- a/packages/quicktype-core/src/input/PathElement.ts +++ b/packages/quicktype-core/src/input/PathElement.ts @@ -2,7 +2,7 @@ export enum PathElementKind { Root = 1, KeyOrIndex = 2, Type = 3, - Object = 4 + Object = 4, } export type PathElement = diff --git a/packages/quicktype-core/src/input/PostmanCollection.ts b/packages/quicktype-core/src/input/PostmanCollection.ts index fd191a8c..cc443268 100644 --- a/packages/quicktype-core/src/input/PostmanCollection.ts +++ b/packages/quicktype-core/src/input/PostmanCollection.ts @@ -1,6 +1,7 @@ import { parseJSON } from "../support/Support"; -import { type JSONSourceData } from "./Inputs"; +import type { JSONSourceData } from "./Inputs"; +import type { JSONSchema } from "./JSONSchemaStore"; function isValidJSON(s: string): boolean { try { @@ -13,20 +14,27 @@ function isValidJSON(s: string): boolean { export function sourcesFromPostmanCollection( collectionJSON: string, - collectionJSONAddress?: string + collectionJSONAddress?: string, ): { description: string | undefined; sources: Array> } { const sources: Array> = []; const descriptions: string[] = []; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function processCollection(c: any): void { - if (typeof c !== "object") return; + function processCollection(c: JSONSchema | undefined): 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") { + if ( + c.info && + typeof c.info === "object" && + "description" in c.info && + typeof c.info?.description === "string" + ) { descriptions.push(c.info.description); } } @@ -34,33 +42,58 @@ export function sourcesFromPostmanCollection( if (typeof c.name === "string" && Array.isArray(c.response)) { const samples: string[] = []; for (const r of c.response) { - if (typeof r === "object" && typeof r.body === "string" && isValidJSON(r.body)) { + if ( + typeof r === "object" && + typeof r.body === "string" && + isValidJSON(r.body) + ) { samples.push(r.body); } } if (samples.length > 0) { - const source: JSONSourceData = { name: c.name, samples }; + const source: JSONSourceData = { + name: c.name, + samples, + }; const sourceDescription = [c.name]; - if (typeof c.request === "object") { - const { method, url } = c.request; - if (method !== undefined && typeof url === "object" && url.raw !== undefined) { + if (c.request && typeof c.request === "object") { + const { method, url } = c.request as { + method: unknown; + url: object; + }; + if ( + method !== undefined && + typeof url === "object" && + "raw" in url && + url.raw !== undefined + ) { sourceDescription.push(`${method} ${url.raw}`); } } - if (typeof c.request === "object" && typeof c.request.description === "string") { + if ( + c.request && + typeof c.request === "object" && + "description" in c.request && + typeof c.request.description === "string" + ) { sourceDescription.push(c.request.description); } - source.description = sourceDescription.length === 0 ? undefined : sourceDescription.join("\n\n"); + source.description = + sourceDescription.length === 0 + ? undefined + : sourceDescription.join("\n\n"); sources.push(source); } } } - processCollection(parseJSON(collectionJSON, "Postman collection", collectionJSONAddress)); + processCollection( + parseJSON(collectionJSON, "Postman collection", collectionJSONAddress), + ); const joinedDescription = descriptions.join("\n\n").trim(); let description: string | undefined = undefined; diff --git a/packages/quicktype-core/src/input/io/NodeIO.ts b/packages/quicktype-core/src/input/io/NodeIO.ts index f93f20a0..d417d8ab 100644 --- a/packages/quicktype-core/src/input/io/NodeIO.ts +++ b/packages/quicktype-core/src/input/io/NodeIO.ts @@ -3,7 +3,7 @@ import * as fs from "fs"; import { defined, exceptionToString } from "@glideapps/ts-necessities"; import { isNode } from "browser-or-node"; import isURL from "is-url"; -import { type Readable } from "readable-stream"; +import type { Readable } from "readable-stream"; import { messageError } from "../../Messages"; import { panic } from "../../support/Support"; @@ -12,7 +12,9 @@ import { getStream } from "./get-stream"; // We need to use cross-fetch in CI or if fetch is not available in the global scope // We use a dynamic import to avoid punycode deprecated dependency warning on node > 20 -const fetch = process.env.CI ? require("cross-fetch").default : (global as any).fetch ?? require("cross-fetch").default; +const fetch = process.env.CI + ? require("cross-fetch").default + : ((global as any).fetch ?? require("cross-fetch").default); interface HttpHeaders { [key: string]: string; @@ -23,7 +25,10 @@ function parseHeaders(httpHeaders?: string[]): HttpHeaders { return {}; } - return httpHeaders.reduce(function (result: HttpHeaders, httpHeader: string) { + return httpHeaders.reduce(( + result: HttpHeaders, + httpHeader: string, + ) => { if (httpHeader !== undefined && httpHeader.length > 0) { const split = httpHeader.indexOf(":"); @@ -40,11 +45,14 @@ 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; @@ -54,24 +62,38 @@ export async function readableFromFileOrURL(fileOrURL: string, httpHeaders?: str return process.stdin as unknown as Readable; } - const filePath = fs.lstatSync(fileOrURL).isSymbolicLink() ? fs.readlinkSync(fileOrURL) : fileOrURL; + const filePath = fs.lstatSync(fileOrURL).isSymbolicLink() + ? fs.readlinkSync(fileOrURL) + : fileOrURL; if (fs.existsSync(filePath)) { // Cast node readable to isomorphic readable from readable-stream - return fs.createReadStream(filePath, "utf8") as unknown as Readable; + return fs.createReadStream( + filePath, + "utf8", + ) as unknown as Readable; } } } catch (e) { - return messageError("MiscReadError", { fileOrURL, message: exceptionToString(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); } catch (e) { - return messageError("MiscReadError", { fileOrURL, message: exceptionToString(e) }); + return messageError("MiscReadError", { + fileOrURL, + message: exceptionToString(e), + }); } } 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 846f6a0a..b578abf3 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,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { PassThrough } from "readable-stream"; -import { type Options } from "."; +import type { Options } from "./index"; + +export interface BufferedPassThrough extends PassThrough { + getBufferedValue: () => any; + getBufferedLength: () => number; + + // for compat with _Readable.Writable + readonly writableObjectMode: never; +} export default function bufferStream(opts: Options) { opts = Object.assign({}, opts); @@ -12,10 +20,8 @@ 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"; } @@ -26,11 +32,11 @@ export default function bufferStream(opts: Options) { let len = 0; const ret: any[] = []; const stream = new PassThrough({ - objectMode - }) as any; + objectMode, + }) as BufferedPassThrough; if (encoding) { - stream.setEncoding(encoding); + stream.setEncoding(encoding as BufferEncoding); } stream.on("data", (chunk: any) => { 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 3f1dcbc4..04c7024b 100644 --- a/packages/quicktype-core/src/input/io/get-stream/index.ts +++ b/packages/quicktype-core/src/input/io/get-stream/index.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { type Readable } from "readable-stream"; +import type { Readable } from "readable-stream"; -import bufferStream from "./buffer-stream"; +import bufferStream, { type BufferedPassThrough } from "./buffer-stream"; export interface Options { array?: boolean; @@ -14,10 +14,10 @@ export async function getStream(inputStream: Readable, opts: Options = {}) { return await Promise.reject(new Error("Expected a stream")); } - opts = Object.assign({ maxBuffer: Infinity }, opts); + opts = Object.assign({ maxBuffer: Number.POSITIVE_INFINITY }, opts); - const maxBuffer = opts.maxBuffer ?? Infinity; - let stream: any; + const maxBuffer = opts.maxBuffer ?? Number.POSITIVE_INFINITY; + let stream: BufferedPassThrough; let clean; const p = new Promise((resolve, reject) => { diff --git a/packages/quicktype-core/src/language/All.ts b/packages/quicktype-core/src/language/All.ts index 637edb37..be1a29a4 100644 --- a/packages/quicktype-core/src/language/All.ts +++ b/packages/quicktype-core/src/language/All.ts @@ -1,4 +1,4 @@ -import { type TargetLanguage } from "../TargetLanguage"; +import type { TargetLanguage } from "../TargetLanguage"; import { CJSONTargetLanguage } from "./CJSON"; import { CPlusPlusTargetLanguage } from "./CPlusPlus"; @@ -23,7 +23,11 @@ import { RustTargetLanguage } from "./Rust"; import { Scala3TargetLanguage } from "./Scala3"; import { SmithyTargetLanguage } from "./Smithy4s"; import { SwiftTargetLanguage } from "./Swift"; -import { type LanguageDisplayName, type LanguageName, type LanguageNameMap } from "./types"; +import type { + LanguageDisplayName, + LanguageName, + LanguageNameMap, +} from "./types"; import { TypeScriptEffectSchemaTargetLanguage } from "./TypeScriptEffectSchema"; import { FlowTargetLanguage, TypeScriptTargetLanguage } from "./TypeScriptFlow"; import { TypeScriptZodTargetLanguage } from "./TypeScriptZod"; @@ -55,16 +59,18 @@ export const all = [ new SwiftTargetLanguage(), new TypeScriptTargetLanguage(), new TypeScriptEffectSchemaTargetLanguage(), - new TypeScriptZodTargetLanguage() + new TypeScriptZodTargetLanguage(), ] as const; all satisfies readonly TargetLanguage[]; export function languageNamed( name: Name, - targetLanguages: readonly TargetLanguage[] = all + targetLanguages: readonly TargetLanguage[] = all, ): LanguageNameMap[Name] { - const foundLanguage = targetLanguages.find(language => language.names.includes(name)); + const foundLanguage = targetLanguages.find((language) => + language.names.includes(name), + ); if (!foundLanguage) { throw new Error(`Unknown language name: ${name}`); } @@ -73,15 +79,21 @@ export function languageNamed( } export function isLanguageName(maybeName: string): maybeName is LanguageName { - if (all.some(lang => (lang.names as readonly string[]).includes(maybeName))) { + if ( + all.some((lang) => + (lang.names as readonly string[]).includes(maybeName), + ) + ) { return true; } return false; } -export function isLanguageDisplayName(maybeName: string): maybeName is LanguageDisplayName { - if (all.some(lang => lang.displayName === maybeName)) { +export function isLanguageDisplayName( + maybeName: string, +): maybeName is LanguageDisplayName { + if (all.some((lang) => lang.displayName === maybeName)) { return true; } diff --git a/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts b/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts index f52702d9..936a0baa 100644 --- a/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts +++ b/packages/quicktype-core/src/language/CJSON/CJSONRenderer.ts @@ -4,19 +4,48 @@ 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 "../../Type/TypeUtils"; +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 "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type cJSONOptions } from "./language"; +import type { cJSONOptions } from "./language"; import { GlobalNames, IncludeKind, @@ -24,7 +53,7 @@ import { type IncludeRecord, type TypeCJSON, type TypeRecord, - legalizeName + legalizeName, } from "./utils"; export class CJSONRenderer extends ConvenienceRenderer { @@ -44,6 +73,8 @@ export class CJSONRenderer extends ConvenienceRenderer { protected readonly enumeratorNamingStyle: NamingStyle; /* Enum naming style */ + private includes: string[]; + /** * Constructor * @param targetLanguage: target language @@ -53,16 +84,23 @@ export class CJSONRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); this.typeIntegerSize = _options.typeIntegerSize; this.hashtableSize = _options.hashtableSize; this.typeNamingStyle = _options.typeNamingStyle; - this.namedTypeNameStyle = makeNameStyle(this.typeNamingStyle, legalizeName); + this.namedTypeNameStyle = makeNameStyle( + this.typeNamingStyle, + legalizeName, + ); this.enumeratorNamingStyle = _options.enumeratorNamingStyle; - this.memberNameStyle = makeNameStyle(_options.memberNamingStyle, legalizeName); + this.memberNameStyle = makeNameStyle( + _options.memberNamingStyle, + legalizeName, + ); this.forbiddenGlobalNames = []; + this.includes = []; for (const type of numberEnumValues(GlobalNames)) { const genName = this.namedTypeNameStyle(GlobalNames[type]); this.forbiddenGlobalNames.push(genName); @@ -81,7 +119,10 @@ 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 }; } @@ -89,7 +130,10 @@ 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 }; } @@ -97,7 +141,10 @@ 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 }; } @@ -130,7 +177,10 @@ export class CJSONRenderer extends ConvenienceRenderer { * @return enum member namer */ protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enumerators", makeNameStyle(this.enumeratorNamingStyle, legalizeName)); + return funPrefixNamer( + "enumerators", + makeNameStyle(this.enumeratorNamingStyle, legalizeName), + ); } /** @@ -145,9 +195,14 @@ export class CJSONRenderer extends ConvenienceRenderer { unionType: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { - let fieldName = super.proposeUnionMemberName(unionType, unionName, fieldType, lookup); + let fieldName = super.proposeUnionMemberName( + unionType, + unionName, + fieldType, + lookup, + ); if ("bool" === fieldName) { fieldName = "boolean"; } else if ("double" === fieldName) { @@ -164,7 +219,13 @@ export class CJSONRenderer extends ConvenienceRenderer { */ protected emitTypedefAlias(fieldType: Type, fieldName: Name): void { if (this._options.addTypedefAlias) { - this.emitLine("typedef ", this.quicktypeTypeToCJSON(fieldType, false).cType, " ", fieldName, ";"); + this.emitLine( + "typedef ", + this.quicktypeTypeToCJSON(fieldType, false).cType, + " ", + fieldName, + ";", + ); this.ensureBlankLine(); } } @@ -191,7 +252,7 @@ export class CJSONRenderer extends ConvenienceRenderer { this.startFile(proposedFilename); /* Create types */ - this.forEachDeclaration("leading-and-interposing", decl => { + this.forEachDeclaration("leading-and-interposing", (decl) => { if (decl.kind === "forward") { this.emitLine("struct ", this.nameForNamedType(decl.type), ";"); } else if (decl.kind === "define") { @@ -213,48 +274,63 @@ export class CJSONRenderer extends ConvenienceRenderer { /* Create top level type */ this.forEachTopLevel( "leading", - (type: Type, className: Name) => this.emitTopLevelTypedef(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined + (type: Type, className: Name) => + this.emitTopLevelTypedef(type, className), + (type) => this.namedTypeToNameForTopLevel(type) === undefined, ); /* Create enum prototypes */ - this.forEachEnum("leading-and-interposing", (enumType: EnumType, _enumName: Name) => - this.emitEnumPrototypes(enumType) + this.forEachEnum( + "leading-and-interposing", + (enumType: EnumType, _enumName: Name) => + this.emitEnumPrototypes(enumType), ); /* Create union prototypes */ - this.forEachUnion("leading-and-interposing", (unionType: UnionType) => this.emitUnionPrototypes(unionType)); + this.forEachUnion("leading-and-interposing", (unionType: UnionType) => + this.emitUnionPrototypes(unionType), + ); /* Create class prototypes */ - this.forEachObject("leading-and-interposing", (classType: ClassType, _className: Name) => - this.emitClassPrototypes(classType) + this.forEachObject( + "leading-and-interposing", + (classType: ClassType, _className: Name) => + this.emitClassPrototypes(classType), ); /* Create top level prototypes */ this.forEachTopLevel( "leading", - (type: Type, className: Name) => this.emitTopLevelPrototypes(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined + (type: Type, className: Name) => + this.emitTopLevelPrototypes(type, className), + (type) => this.namedTypeToNameForTopLevel(type) === undefined, ); /* Create enum functions */ - this.forEachEnum("leading-and-interposing", (enumType: EnumType, _enumName: Name) => - this.emitEnumFunctions(enumType) + this.forEachEnum( + "leading-and-interposing", + (enumType: EnumType, _enumName: Name) => + this.emitEnumFunctions(enumType), ); /* Create union functions */ - this.forEachUnion("leading-and-interposing", (unionType: UnionType) => this.emitUnionFunctions(unionType)); + this.forEachUnion("leading-and-interposing", (unionType: UnionType) => + this.emitUnionFunctions(unionType), + ); /* Create class functions */ - this.forEachObject("leading-and-interposing", (classType: ClassType, _className: Name) => - this.emitClassFunctions(classType) + this.forEachObject( + "leading-and-interposing", + (classType: ClassType, _className: Name) => + this.emitClassFunctions(classType), ); /* Create top level functions */ this.forEachTopLevel( "leading", - (type: Type, className: Name) => this.emitTopLevelFunctions(type, className), - type => this.namedTypeToNameForTopLevel(type) === undefined + (type: Type, className: Name) => + this.emitTopLevelFunctions(type, className), + (type) => this.namedTypeToNameForTopLevel(type) === undefined, ); /* Close file */ @@ -265,41 +341,38 @@ export class CJSONRenderer extends ConvenienceRenderer { * Function called to create a multiple header files with types and generators */ protected emitMultiSourceStructure(): void { - /* Array of includes */ - let includes: string[]; - /* Create each file */ this.forEachNamedType( "leading-and-interposing", (classType: ClassType, _name: Name) => { - this.emitClass(classType, includes); + this.emitClass(classType); }, (enumType, _name) => { - this.emitEnum(enumType, includes); + this.emitEnum(enumType); }, (unionType, _name) => { - this.emitUnion(unionType, includes); - } + this.emitUnion(unionType); + }, ); /* Create top level file */ this.forEachTopLevel( "leading", - (type: Type, className: Name) => this.emitTopLevel(type, className, includes), - type => this.namedTypeToNameForTopLevel(type) === undefined + (type: Type, className: Name) => + this.emitTopLevel(type, className, this.includes), + (type) => this.namedTypeToNameForTopLevel(type) === undefined, ); } /** * Function called to create an enum header files with types and generators * @param enumType: enum type - * @param includes: Array of includes */ - protected emitEnum(enumType: EnumType, includes: string[]): void { + protected emitEnum(enumType: EnumType): void { /* Create file */ const enumName = this.nameForNamedType(enumType); const filename = this.sourcelikeToString(enumName).concat(".h"); - includes.push(filename); + this.includes.push(filename); this.startFile(filename); /* Create includes */ @@ -332,12 +405,24 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock( ["enum ", enumName], () => { - const combinedName = allUpperWordStyle(this.sourcelikeToString(enumName)); + const combinedName = allUpperWordStyle( + this.sourcelikeToString(enumName), + ); this.forEachEnumCase(enumType, "none", (name, jsonName) => { if (enumValues !== undefined) { - const [enumValue] = getAccessorName(enumValues, jsonName); + const [enumValue] = getAccessorName( + enumValues, + jsonName, + ); if (enumValue !== undefined) { - this.emitLine(combinedName, "_", name, " = ", enumValue.toString(), ","); + this.emitLine( + combinedName, + "_", + name, + " = ", + enumValue.toString(), + ",", + ); } else { this.emitLine(combinedName, "_", name, ","); } @@ -347,7 +432,7 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypedefAlias(enumType, enumName); @@ -360,8 +445,22 @@ export class CJSONRenderer extends ConvenienceRenderer { protected emitEnumPrototypes(enumType: EnumType): void { const enumName = this.nameForNamedType(enumType); - this.emitLine("enum ", enumName, " cJSON_Get", enumName, "Value(", this.withConst("cJSON"), " * j);"); - this.emitLine("cJSON * cJSON_Create", enumName, "(", this.withConst(["enum ", enumName]), " x);"); + this.emitLine( + "enum ", + enumName, + " cJSON_Get", + enumName, + "Value(", + this.withConst("cJSON"), + " * j);", + ); + this.emitLine( + "cJSON * cJSON_Create", + enumName, + "(", + this.withConst(["enum ", enumName]), + " x);", + ); this.ensureBlankLine(); } @@ -373,61 +472,84 @@ export class CJSONRenderer extends ConvenienceRenderer { const enumName = this.nameForNamedType(enumType); /* Create cJSON to enumName generator function */ - this.emitBlock(["enum ", enumName, " cJSON_Get", enumName, "Value(", this.withConst("cJSON"), " * j)"], () => { - this.emitLine("enum ", enumName, " x = 0;"); - this.emitBlock(["if (NULL != j)"], () => { - let onFirst = true; - const combinedName = allUpperWordStyle(this.sourcelikeToString(enumName)); - this.forEachEnumCase(enumType, "none", (name, jsonName) => { - this.emitLine( - onFirst ? "" : "else ", - 'if (!strcmp(cJSON_GetStringValue(j), "', - jsonName, - '")) x = ', - combinedName, - "_", - name, - ";" + this.emitBlock( + [ + "enum ", + enumName, + " cJSON_Get", + enumName, + "Value(", + this.withConst("cJSON"), + " * j)", + ], + () => { + this.emitLine("enum ", enumName, " x = 0;"); + this.emitBlock(["if (NULL != j)"], () => { + let onFirst = true; + const combinedName = allUpperWordStyle( + this.sourcelikeToString(enumName), ); - onFirst = false; + this.forEachEnumCase(enumType, "none", (name, jsonName) => { + this.emitLine( + onFirst ? "" : "else ", + 'if (!strcmp(cJSON_GetStringValue(j), "', + jsonName, + '")) x = ', + combinedName, + "_", + name, + ";", + ); + onFirst = false; + }); }); - }); - this.emitLine("return x;"); - }); + this.emitLine("return x;"); + }, + ); this.ensureBlankLine(); /* Create enumName to cJSON generator function */ - this.emitBlock(["cJSON * cJSON_Create", enumName, "(", this.withConst(["enum ", enumName]), " x)"], () => { - this.emitLine("cJSON * j = NULL;"); - this.emitBlock(["switch (x)"], () => { - const combinedName = allUpperWordStyle(this.sourcelikeToString(enumName)); - this.forEachEnumCase(enumType, "none", (name, jsonName) => { - this.emitLine( - "case ", - combinedName, - "_", - name, - ': j = cJSON_CreateString("', - jsonName, - '"); break;' + this.emitBlock( + [ + "cJSON * cJSON_Create", + enumName, + "(", + this.withConst(["enum ", enumName]), + " x)", + ], + () => { + this.emitLine("cJSON * j = NULL;"); + this.emitBlock(["switch (x)"], () => { + const combinedName = allUpperWordStyle( + this.sourcelikeToString(enumName), ); + this.forEachEnumCase(enumType, "none", (name, jsonName) => { + this.emitLine( + "case ", + combinedName, + "_", + name, + ': j = cJSON_CreateString("', + jsonName, + '"); break;', + ); + }); }); - }); - this.emitLine("return j;"); - }); + this.emitLine("return j;"); + }, + ); this.ensureBlankLine(); } /** * Function called to create a union header files with types and generators * @param unionType: union type - * @param includes: Array of includes */ - protected emitUnion(unionType: UnionType, includes: string[]): void { + protected emitUnion(unionType: UnionType): void { /* Create file */ const unionName = this.nameForNamedType(unionType); const filename = this.sourcelikeToString(unionName).concat(".h"); - includes.push(filename); + this.includes.push(filename); this.startFile(filename); /* Create includes */ @@ -464,23 +586,26 @@ export class CJSONRenderer extends ConvenienceRenderer { ["union"], () => { for (const type of nonNulls) { - const cJSON = this.quicktypeTypeToCJSON(type, false); + const cJSON = this.quicktypeTypeToCJSON( + type, + false, + ); this.emitLine( cJSON.cType, cJSON.optionalQualifier !== "" ? " " : "", cJSON.optionalQualifier, " ", this.nameForUnionMember(unionType, type), - ";" + ";", ); } }, "value", - true + true, ); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypedefAlias(unionType, unionName); @@ -493,9 +618,27 @@ export class CJSONRenderer extends ConvenienceRenderer { protected emitUnionPrototypes(unionType: UnionType): void { const unionName = this.nameForNamedType(unionType); - this.emitLine("struct ", unionName, " * cJSON_Get", unionName, "Value(const cJSON * j);"); - this.emitLine("cJSON * cJSON_Create", unionName, "(", this.withConst(["struct ", unionName]), " * x);"); - this.emitLine("void cJSON_Delete", unionName, "(struct ", unionName, " * x);"); + this.emitLine( + "struct ", + unionName, + " * cJSON_Get", + unionName, + "Value(const cJSON * j);", + ); + this.emitLine( + "cJSON * cJSON_Create", + unionName, + "(", + this.withConst(["struct ", unionName]), + " * x);", + ); + this.emitLine( + "void cJSON_Delete", + unionName, + "(struct ", + unionName, + " * x);", + ); this.ensureBlankLine(); } @@ -508,325 +651,550 @@ export class CJSONRenderer extends ConvenienceRenderer { const unionName = this.nameForNamedType(unionType); /* Create cJSON to unionType generator function */ - this.emitBlock(["struct ", unionName, " * cJSON_Get", unionName, "Value(const cJSON * j)"], () => { - let onFirst = true; - this.emitLine("struct ", unionName, " * x = cJSON_malloc(sizeof(struct ", unionName, "));"); - this.emitBlock(["if (NULL != x)"], () => { - this.emitLine("memset(x, 0, sizeof(struct ", unionName, "));"); - if (hasNull !== null) { - this.emitBlock(["if (cJSON_IsNull(j))"], () => { - this.emitLine("x->type = cJSON_NULL;"); - }); - onFirst = false; - } + this.emitBlock( + [ + "struct ", + unionName, + " * cJSON_Get", + unionName, + "Value(const cJSON * j)", + ], + () => { + let onFirst = true; + this.emitLine( + "struct ", + unionName, + " * x = cJSON_malloc(sizeof(struct ", + unionName, + "));", + ); + this.emitBlock(["if (NULL != x)"], () => { + this.emitLine( + "memset(x, 0, sizeof(struct ", + unionName, + "));", + ); + if (hasNull !== null) { + this.emitBlock(["if (cJSON_IsNull(j))"], () => { + this.emitLine("x->type = cJSON_NULL;"); + }); + onFirst = false; + } - for (const type of nonNulls) { - const cJSON = this.quicktypeTypeToCJSON(type, false); - this.emitBlock([onFirst === true ? "if (" : "else if (", cJSON.isType, "(j))"], () => { - this.emitLine("x->type = ", cJSON.cjsonType, ";"); - if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { - const level = 0; - const child_level = 1; - this.emitLine(cJSON.cType, " * x", child_level.toString(), " = list_create(false, NULL);"); - this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { - this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); - this.emitBlock( - [ - "cJSON_ArrayForEach(e", + for (const type of nonNulls) { + const cJSON = this.quicktypeTypeToCJSON(type, false); + this.emitBlock( + [ + onFirst === true ? "if (" : "else if (", + cJSON.isType, + "(j))", + ], + () => { + this.emitLine( + "x->type = ", + cJSON.cjsonType, + ";", + ); + if ( + cJSON.cjsonType === "cJSON_Array" && + cJSON.items !== undefined + ) { + const level = 0; + const child_level = 1; + this.emitLine( + cJSON.cType, + " * x", child_level.toString(), - ", j", - level > 0 ? level.toString() : "", - ")" - ], - () => { - const add = (cJSON: TypeCJSON, level: number, child_level: number) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "list_add_tail(x", + " = list_create(false, NULL);", + ); + this.emitBlock( + [ + "if (NULL != x", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + "cJSON * e", + child_level.toString(), + " = NULL;", + ); + this.emitBlock( + [ + "cJSON_ArrayForEach(e", child_level.toString(), - ", (", - cJSON.items?.cType, - " *)0xDEADBEEF, sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if (cJSON.items?.cjsonType === "cJSON_String") { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", strdup(", - cJSON.items?.getValue, - "(e", - child_level.toString(), - ")), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if ( - cJSON.items?.cjsonType === "cJSON_Object" || - cJSON.items?.cjsonType === "cJSON_Union" - ) { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", ", - cJSON.items?.getValue, - "(e", - child_level.toString(), - "), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * tmp", - level > 0 ? level.toString() : "", - " = cJSON_malloc(sizeof(", - cJSON.items?.cType, - "));" - ); - this.emitBlock( - ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], - () => { - this.emitLine( - "* tmp", - level > 0 ? level.toString() : "", - " = ", - // @ts-expect-error awaiting refactor - cJSON.items?.getValue, - "(e", - child_level.toString(), - ");" + ", j", + level > 0 + ? level.toString() + : "", + ")", + ], + () => { + const add = ( + cJSON: TypeCJSON, + level: number, + child_level: number, + ) => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Invalid" || + cJSON.items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", (", + cJSON.items + ?.cType, + " *)0xDEADBEEF, sizeof(", + cJSON.items + ?.cType, + " *));", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", strdup(", + cJSON.items + ?.getValue, + "(e", + child_level.toString(), + ")), sizeof(", + cJSON.items + ?.cType, + " *));", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Object" || + cJSON.items + ?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", ", + cJSON.items + ?.getValue, + "(e", + child_level.toString(), + "), sizeof(", + cJSON.items + ?.cType, + " *));", + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items + ?.cType, + " * tmp", + level > 0 + ? level.toString() + : "", + " = cJSON_malloc(sizeof(", + cJSON.items + ?.cType, + "));", + ); + this.emitBlock( + [ + "if (NULL != tmp", + level > 0 + ? level.toString() + : "", + ")", + ], + () => { + this.emitLine( + "* tmp", + level > + 0 + ? level.toString() + : "", + " = ", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + ");", + ); + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", tmp", + level > + 0 + ? level.toString() + : "", + ", sizeof(", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.cType, + " *));", + ); + }, + ); + } + }; + + if ( + cJSON.items?.isNullable + ) { + this.emitBlock( + [ + "if (!cJSON_IsNull(e", + child_level.toString(), + "))", + ], + () => { + add( + cJSON, + level, + child_level, + ); + }, ); - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", tmp", - level > 0 ? level.toString() : "", - ", sizeof(", - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *));" + this.emitBlock( + ["else"], + () => { + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", (void *)0xDEADBEEF, sizeof(void *));", + ); + }, + ); + } else { + add( + cJSON, + level, + child_level, ); } - ); - } - }; - - 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 *));" - ); - }); - } 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) { - const level = 0; - const child_level = 1; - this.emitLine( - cJSON.cType, - " * x", - child_level.toString(), - " = hashtable_create(", - this.hashtableSize, - ", false);" - ); - this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { - this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); - this.emitBlock( - [ - "cJSON_ArrayForEach(e", + this.emitLine( + "x->value.", + this.nameForUnionMember( + unionType, + type, + ), + " = x", + child_level.toString(), + ";", + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Map" && + cJSON.items !== undefined + ) { + const level = 0; + const child_level = 1; + this.emitLine( + cJSON.cType, + " * x", child_level.toString(), - ", j", - level > 0 ? level.toString() : "", - ")" - ], - () => { - const add = (cJSON: TypeCJSON, level: number, child_level: number) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "hashtable_add(x", + " = hashtable_create(", + this.hashtableSize, + ", false);", + ); + this.emitBlock( + [ + "if (NULL != x", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + "cJSON * e", + child_level.toString(), + " = NULL;", + ); + this.emitBlock( + [ + "cJSON_ArrayForEach(e", child_level.toString(), - ", e", - child_level.toString(), - "->string, (", - cJSON.items?.cType, - " *)0xDEADBEEF, sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if (cJSON.items?.cjsonType === "cJSON_String") { - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, strdup(", - cJSON.items?.getValue, - "(e", - child_level.toString(), - ")), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if ( - cJSON.items?.cjsonType === "cJSON_Object" || - cJSON.items?.cjsonType === "cJSON_Union" - ) { - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, ", - cJSON.items?.getValue, - "(e", - child_level.toString(), - "), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * tmp", - level > 0 ? level.toString() : "", - " = cJSON_malloc(sizeof(", - cJSON.items?.cType, - "));" - ); - this.emitBlock( - ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], - () => { - this.emitLine( - "* tmp", - level > 0 ? level.toString() : "", - " = ", - // @ts-expect-error awaiting refactor - cJSON.items?.getValue, - "(e", - child_level.toString(), - ");" + ", j", + level > 0 + ? level.toString() + : "", + ")", + ], + () => { + const add = ( + cJSON: TypeCJSON, + level: number, + child_level: number, + ) => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Invalid" || + cJSON.items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, (", + cJSON.items + ?.cType, + " *)0xDEADBEEF, sizeof(", + cJSON.items + ?.cType, + " *));", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, strdup(", + cJSON.items + ?.getValue, + "(e", + child_level.toString(), + ")), sizeof(", + cJSON.items + ?.cType, + " *));", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Object" || + cJSON.items + ?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, ", + cJSON.items + ?.getValue, + "(e", + child_level.toString(), + "), sizeof(", + cJSON.items + ?.cType, + " *));", + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items + ?.cType, + " * tmp", + level > 0 + ? level.toString() + : "", + " = cJSON_malloc(sizeof(", + cJSON.items + ?.cType, + "));", + ); + this.emitBlock( + [ + "if (NULL != tmp", + level > 0 + ? level.toString() + : "", + ")", + ], + () => { + this.emitLine( + "* tmp", + level > + 0 + ? level.toString() + : "", + " = ", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + ");", + ); + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, tmp", + level > + 0 + ? level.toString() + : "", + ", sizeof(", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.cType, + " *));", + ); + }, + ); + } + }; + + if ( + cJSON.items?.isNullable + ) { + this.emitBlock( + [ + "if (!cJSON_IsNull(e", + child_level.toString(), + "))", + ], + () => { + add( + cJSON, + level, + child_level, + ); + }, ); - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, tmp", - level > 0 ? level.toString() : "", - ", sizeof(", - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *));" + this.emitBlock( + ["else"], + () => { + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, (void *)0xDEADBEEF, sizeof(void *));", + ); + }, + ); + } else { + add( + cJSON, + level, + child_level, ); } - ); - } - }; - - if (cJSON.items?.isNullable) { - this.emitBlock( - ["if (!cJSON_IsNull(e", child_level.toString(), "))"], - () => { - add(cJSON, level, child_level); - } + }, ); - this.emitBlock(["else"], () => { - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->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") { - this.emitLine( - "x->value.", - this.nameForUnionMember(unionType, type), - " = (", - cJSON.cType, - " *)0xDEADBEEF;" - ); - } else if (cJSON.cjsonType === "cJSON_String") { - this.emitLine( - "x->value.", - this.nameForUnionMember(unionType, type), - " = strdup(", - cJSON.getValue, - "(j));" - ); - } else { - this.emitLine( - "x->value.", - this.nameForUnionMember(unionType, type), - " = ", - cJSON.getValue, - "(j);" - ); - } - }); - onFirst = false; - } - }); - this.emitLine("return x;"); - }); + this.emitLine( + "x->value.", + this.nameForUnionMember( + unionType, + type, + ), + " = x", + child_level.toString(), + ";", + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Invalid" || + cJSON.cjsonType === "cJSON_NULL" + ) { + this.emitLine( + "x->value.", + this.nameForUnionMember( + unionType, + type, + ), + " = (", + cJSON.cType, + " *)0xDEADBEEF;", + ); + } else if (cJSON.cjsonType === "cJSON_String") { + this.emitLine( + "x->value.", + this.nameForUnionMember( + unionType, + type, + ), + " = strdup(", + cJSON.getValue, + "(j));", + ); + } else { + this.emitLine( + "x->value.", + this.nameForUnionMember( + unionType, + type, + ), + " = ", + cJSON.getValue, + "(j);", + ); + } + }, + ); + onFirst = false; + } + }); + this.emitLine("return x;"); + }, + ); this.ensureBlankLine(); /* Create unionName to cJSON generator function */ this.emitBlock( - ["cJSON * cJSON_Create", unionName, "(", this.withConst(["struct ", unionName]), " * x)"], + [ + "cJSON * cJSON_Create", + unionName, + "(", + this.withConst(["struct ", unionName]), + " * x)", + ], () => { this.emitLine("cJSON * j = NULL;"); this.emitBlock(["if (NULL != x)"], () => { @@ -841,9 +1209,16 @@ export class CJSONRenderer extends ConvenienceRenderer { for (const type of nonNulls) { const cJSON = this.quicktypeTypeToCJSON(type, false); this.emitBlock( - [onFirst === true ? "if (" : "else if (", cJSON.cjsonType, " == x->type)"], + [ + onFirst === true ? "if (" : "else if (", + cJSON.cjsonType, + " == x->type)", + ], () => { - if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { + if ( + cJSON.cjsonType === "cJSON_Array" && + cJSON.items !== undefined + ) { const level = 0; const child_level = 1; this.emitLine( @@ -851,486 +1226,779 @@ export class CJSONRenderer extends ConvenienceRenderer { child_level.toString(), " = ", cJSON.createObject, - "();" + "();", ); - this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * x", + this.emitBlock( + [ + "if (NULL != j", child_level.toString(), - " = list_get_head(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ");" - ); - this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { - const add = (cJSON: TypeCJSON, child_level: number) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.items?.cjsonType === "cJSON_NULL") { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", ", - cJSON.items?.createObject, - "());" - ); - } else if ( - 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, - "(x", - child_level.toString(), - "));" - ); - } else { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", ", - // @ts-expect-error awaiting refactor - 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());" - ); - }); - } else { - add(cJSON, child_level); - } - + ")", + ], + () => { this.emitLine( - "x", + // @ts-expect-error awaiting refactor + cJSON.items?.cType, + " * x", child_level.toString(), - " = list_get_next(x", - level > 0 ? level.toString() : "", + " = list_get_head(x", + level > 0 + ? level.toString() + : "", "->value.", - this.nameForUnionMember(unionType, type), - ");" + this.nameForUnionMember( + unionType, + type, + ), + ");", ); - }); - this.emitLine("j = j", child_level.toString(), ";"); - }); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { - const level = 0; - const child_level = 1; - this.emitLine( - "cJSON * j", - child_level.toString(), - " = ", - cJSON.createObject, - "();" - ); - this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { - this.emitLine("char **keys", child_level.toString(), " = NULL;"); - this.emitLine( - "size_t count", - child_level.toString(), - " = hashtable_get_keys(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ", &keys", - child_level.toString(), - ");" - ); - this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { this.emitBlock( [ - "for (size_t index", + "while (NULL != x", child_level.toString(), - " = 0; index", - child_level.toString(), - " < count", - child_level.toString(), - "; index", - child_level.toString(), - "++)" + ")", ], () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *x", - child_level.toString(), - " = hashtable_lookup(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "]);" - ); - const add = (cJSON: TypeCJSON, child_level: number) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { + const add = ( + cJSON: TypeCJSON, + child_level: number, + ) => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.items?.cjsonType === "cJSON_NULL") { - this.emitLine( - cJSON.addToObject, - "(j", - child_level.toString(), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "], ", - cJSON.items?.createObject, - "());" - ); } else if ( - cJSON.items?.cjsonType === "cJSON_String" || - cJSON.items?.cjsonType === "cJSON_Object" || - cJSON.items?.cjsonType === "cJSON_Union" + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_NULL" ) { this.emitLine( - cJSON.addToObject, - "(j", + "cJSON_AddItemToArray(j", child_level.toString(), - ", keys", + ", ", + cJSON.items + ?.createObject, + "());", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_String" || + cJSON.items + ?.cjsonType === + "cJSON_Object" || + cJSON.items + ?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "cJSON_AddItemToArray(j", child_level.toString(), - "[index", - child_level.toString(), - "], ", - cJSON.items?.createObject, + ", ", + cJSON.items + ?.createObject, "(x", child_level.toString(), - "));" + "));", ); } else { this.emitLine( - cJSON.addToObject, - "(j", + "cJSON_AddItemToArray(j", child_level.toString(), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "], ", + ", ", // @ts-expect-error awaiting refactor - cJSON.items?.createObject, + cJSON.items + ?.createObject, "(*x", child_level.toString(), - "));" + "));", ); } }; - if (cJSON.items?.isNullable) { + if ( + cJSON.items?.isNullable + ) { this.emitBlock( [ "if ((void *)0xDEADBEEF != x", child_level.toString(), - ")" + ")", ], () => { - add(cJSON, child_level); - } + add( + cJSON, + child_level, + ); + }, ); - this.emitBlock(["else"], () => { + this.emitBlock( + ["else"], + () => { + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", cJSON_CreateNull());", + ); + }, + ); + } else { + add(cJSON, child_level); + } + + this.emitLine( + "x", + child_level.toString(), + " = list_get_next(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ");", + ); + }, + ); + this.emitLine( + "j = j", + child_level.toString(), + ";", + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Map" && + cJSON.items !== undefined + ) { + const level = 0; + const child_level = 1; + this.emitLine( + "cJSON * j", + child_level.toString(), + " = ", + cJSON.createObject, + "();", + ); + this.emitBlock( + [ + "if (NULL != j", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + "char **keys", + child_level.toString(), + " = NULL;", + ); + this.emitLine( + "size_t count", + child_level.toString(), + " = hashtable_get_keys(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ", &keys", + child_level.toString(), + ");", + ); + this.emitBlock( + [ + "if (NULL != keys", + child_level.toString(), + ")", + ], + () => { + this.emitBlock( + [ + "for (size_t index", + child_level.toString(), + " = 0; index", + child_level.toString(), + " < count", + child_level.toString(), + "; index", + child_level.toString(), + "++)", + ], + () => { this.emitLine( - cJSON.addToObject, - "(j", + // @ts-expect-error awaiting refactor + cJSON.items + ?.cType, + " *x", child_level.toString(), + " = hashtable_lookup(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), ", keys", child_level.toString(), "[index", child_level.toString(), - "], cJSON_CreateNull());" + "]);", ); - }); - } else { - add(cJSON, child_level); - } - } + const add = ( + cJSON: TypeCJSON, + child_level: number, + ) => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + cJSON.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], ", + cJSON + .items + ?.createObject, + "());", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_String" || + cJSON.items + ?.cjsonType === + "cJSON_Object" || + cJSON.items + ?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + cJSON.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], ", + cJSON + .items + ?.createObject, + "(x", + child_level.toString(), + "));", + ); + } else { + this.emitLine( + cJSON.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], ", + // @ts-expect-error awaiting refactor + 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.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], cJSON_CreateNull());", + ); + }, + ); + } else { + add( + cJSON, + child_level, + ); + } + }, + ); + this.emitLine( + "cJSON_free(keys", + child_level.toString(), + ");", + ); + }, ); - this.emitLine("cJSON_free(keys", child_level.toString(), ");"); - }); - this.emitLine("j = j", child_level.toString(), ";"); - }); - } else if (cJSON.cjsonType === "cJSON_Invalid") { + this.emitLine( + "j = j", + child_level.toString(), + ";", + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Invalid" + ) { /* Nothing to do */ } else if (cJSON.cjsonType === "cJSON_NULL") { - this.emitLine("j = ", cJSON.createObject, "();"); + this.emitLine( + "j = ", + cJSON.createObject, + "();", + ); } else { this.emitLine( "j = ", cJSON.createObject, "(x->value.", - this.nameForUnionMember(unionType, type), - ");" + this.nameForUnionMember( + unionType, + type, + ), + ");", ); } - } + }, ); onFirst = false; } }); this.emitLine("return j;"); - } + }, ); this.ensureBlankLine(); /* Create unionName delete function */ - this.emitBlock(["void cJSON_Delete", unionName, "(struct ", unionName, " * x)"], () => { - this.emitBlock(["if (NULL != x)"], () => { - let onFirst = true; - for (const type of nonNulls) { - const cJSON = this.quicktypeTypeToCJSON(type, false); - this.emitBlock([onFirst === true ? "if (" : "else if (", cJSON.cjsonType, " == x->type)"], () => { - if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { - const level = 0; - const child_level = 1; - this.emitBlock( - [ - "if (NULL != x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ")" - ], - () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * x", - child_level.toString(), - " = list_get_head(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ");" - ); - this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - /* Nothing to do */ - } else { - if (cJSON.items?.isNullable) { - this.emitBlock( - ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], - () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } - ); - } else { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } - } - - this.emitLine( - "x", - child_level.toString(), - " = list_get_next(x", + this.emitBlock( + ["void cJSON_Delete", unionName, "(struct ", unionName, " * x)"], + () => { + this.emitBlock(["if (NULL != x)"], () => { + let onFirst = true; + for (const type of nonNulls) { + const cJSON = this.quicktypeTypeToCJSON(type, false); + this.emitBlock( + [ + onFirst === true ? "if (" : "else if (", + cJSON.cjsonType, + " == x->type)", + ], + () => { + if ( + cJSON.cjsonType === "cJSON_Array" && + cJSON.items !== undefined + ) { + const level = 0; + const child_level = 1; + this.emitBlock( + [ + "if (NULL != x", level > 0 ? level.toString() : "", "->value.", - this.nameForUnionMember(unionType, type), - ");" - ); - }); - this.emitLine( - cJSON.deleteType, - "(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ");" - ); - } - ); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { - const level = 0; - const child_level = 1; - this.emitBlock( - [ - "if (NULL != x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ")" - ], - () => { - this.emitLine("char **keys", child_level.toString(), " = NULL;"); - this.emitLine( - "size_t count", - child_level.toString(), - " = hashtable_get_keys(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ", &keys", - child_level.toString(), - ");" - ); - this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { - this.emitBlock( - [ - "for (size_t index", + this.nameForUnionMember( + unionType, + type, + ), + ")", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items?.cType, + " * x", child_level.toString(), - " = 0; index", - child_level.toString(), - " < count", - child_level.toString(), - "; index", - child_level.toString(), - "++)" - ], - () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *x", + " = list_get_head(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ");", + ); + this.emitBlock( + [ + "while (NULL != x", child_level.toString(), - " = hashtable_lookup(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "]);" - ); - this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { + ")", + ], + () => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { /* Not supported */ } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + 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( // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, + cJSON + .items + ?.deleteType, "(x", child_level.toString(), - ");" + ");", ); - } + }, ); } else { this.emitLine( // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, + cJSON.items + ?.deleteType, "(x", child_level.toString(), - ");" + ");", ); } } - }); - } - ); - this.emitLine("cJSON_free(keys", child_level.toString(), ");"); - }); + + this.emitLine( + "x", + child_level.toString(), + " = list_get_next(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ");", + ); + }, + ); + this.emitLine( + cJSON.deleteType, + "(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ");", + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Map" && + cJSON.items !== undefined + ) { + const level = 0; + const child_level = 1; + this.emitBlock( + [ + "if (NULL != x", + level > 0 ? level.toString() : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ")", + ], + () => { + this.emitLine( + "char **keys", + child_level.toString(), + " = NULL;", + ); + this.emitLine( + "size_t count", + child_level.toString(), + " = hashtable_get_keys(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ", &keys", + child_level.toString(), + ");", + ); + this.emitBlock( + [ + "if (NULL != keys", + child_level.toString(), + ")", + ], + () => { + this.emitBlock( + [ + "for (size_t index", + child_level.toString(), + " = 0; index", + child_level.toString(), + " < count", + child_level.toString(), + "; index", + child_level.toString(), + "++)", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items + ?.cType, + " *x", + child_level.toString(), + " = hashtable_lookup(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "]);", + ); + this.emitBlock( + [ + "if (NULL != x", + child_level.toString(), + ")", + ], + () => { + if ( + cJSON + .items + ?.cjsonType === + "cJSON_Array" + ) { + /* Not supported */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Invalid" || + cJSON + .items + ?.cjsonType === + "cJSON_NULL" + ) { + /* Nothing to do */ + } else { + if ( + cJSON + .items + ?.isNullable + ) { + this.emitBlock( + [ + "if ((void *)0xDEADBEEF != x", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON + .items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + }, + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON + .items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + } + } + }, + ); + }, + ); + this.emitLine( + "cJSON_free(keys", + child_level.toString(), + ");", + ); + }, + ); + this.emitLine( + cJSON.deleteType, + "(x", + level > 0 + ? level.toString() + : "", + "->value.", + this.nameForUnionMember( + unionType, + type, + ), + ");", + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Invalid" || + cJSON.cjsonType === "cJSON_NULL" + ) { + /* Nothing to do */ + } else if ( + cJSON.cjsonType === "cJSON_String" || + cJSON.cjsonType === "cJSON_Object" || + cJSON.cjsonType === "cJSON_Union" + ) { this.emitLine( cJSON.deleteType, - "(x", - level > 0 ? level.toString() : "", - "->value.", - this.nameForUnionMember(unionType, type), - ");" + "(x->value.", + this.nameForUnionMember( + unionType, + type, + ), + ");", ); + } else { + /* Nothing to do */ } - ); - } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { - /* Nothing to do */ - } else if ( - cJSON.cjsonType === "cJSON_String" || - cJSON.cjsonType === "cJSON_Object" || - cJSON.cjsonType === "cJSON_Union" - ) { - this.emitLine( - cJSON.deleteType, - "(x->value.", - this.nameForUnionMember(unionType, type), - ");" - ); - } else { - /* Nothing to do */ - } - }); - onFirst = false; - } + }, + ); + onFirst = false; + } - this.emitLine("cJSON_free(x);"); - }); - }); + this.emitLine("cJSON_free(x);"); + }); + }, + ); this.ensureBlankLine(); } /** * Function called to create a class header files with types and generators * @param classType: class type - * @param includes: Array of includes */ - protected emitClass(classType: ClassType, includes: string[]): void { + protected emitClass(classType: ClassType): void { /* Create file */ const className = this.nameForNamedType(classType); const filename = this.sourcelikeToString(className).concat(".h"); - includes.push(filename); + this.includes.push(filename); this.startFile(filename); /* Create includes */ @@ -1360,21 +2028,33 @@ export class CJSONRenderer extends ConvenienceRenderer { this.emitBlock( ["struct ", className], () => { - this.forEachClassProperty(classType, "none", (name, jsonName, property) => { - this.emitDescription(this.descriptionForClassProperty(classType, jsonName)); - const cJSON = this.quicktypeTypeToCJSON(property.type, property.isOptional); - this.emitLine( - cJSON.cType, - cJSON.optionalQualifier !== "" ? " " : "", - cJSON.optionalQualifier, - " ", - name, - ";" - ); - }); + this.forEachClassProperty( + classType, + "none", + (name, jsonName, property) => { + this.emitDescription( + this.descriptionForClassProperty( + classType, + jsonName, + ), + ); + const cJSON = this.quicktypeTypeToCJSON( + property.type, + property.isOptional, + ); + this.emitLine( + cJSON.cType, + cJSON.optionalQualifier !== "" ? " " : "", + cJSON.optionalQualifier, + " ", + name, + ";", + ); + }, + ); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypedefAlias(classType, className); @@ -1387,11 +2067,45 @@ export class CJSONRenderer extends ConvenienceRenderer { protected emitClassPrototypes(classType: ClassType): void { const className = this.nameForNamedType(classType); - 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);"); - this.emitLine("char * cJSON_Print", className, "(", this.withConst(["struct ", className]), " * x);"); - this.emitLine("void cJSON_Delete", className, "(struct ", className, " * x);"); + 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);", + ); + this.emitLine( + "char * cJSON_Print", + className, + "(", + this.withConst(["struct ", className]), + " * x);", + ); + this.emitLine( + "void cJSON_Delete", + className, + "(struct ", + className, + " * x);", + ); this.ensureBlankLine(); } @@ -1404,7 +2118,15 @@ export class CJSONRenderer extends ConvenienceRenderer { /* Create string to className generator function */ this.emitBlock( - ["struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s)"], + [ + "struct ", + className, + " * cJSON_Parse", + className, + "(", + this.withConst("char"), + " * s)", + ], () => { this.emitLine("struct ", className, " * x = NULL;"); this.emitBlock(["if (NULL != s)"], () => { @@ -1415,1529 +2137,2470 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); /* Create cJSON to className generator function */ this.emitBlock( - ["struct ", className, " * cJSON_Get", className, "Value(", this.withConst("cJSON"), " * j)"], + [ + "struct ", + className, + " * cJSON_Get", + className, + "Value(", + this.withConst("cJSON"), + " * j)", + ], () => { this.emitLine("struct ", className, " * x = NULL;"); this.emitBlock(["if (NULL != j)"], () => { - this.emitBlock(["if (NULL != (x = cJSON_malloc(sizeof(struct ", className, "))))"], () => { - this.emitLine("memset(x, 0, sizeof(struct ", className, "));"); - const recur = (type: Type, level: number) => { - if (type instanceof ArrayType) { - const child_level = level + 1; - const cJSON = this.quicktypeTypeToCJSON(type.items, false); - this.emitLine("list_t * x", child_level.toString(), " = list_create(false, NULL);"); - this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { - this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); + this.emitBlock( + [ + "if (NULL != (x = cJSON_malloc(sizeof(struct ", + className, + "))))", + ], + () => { + this.emitLine( + "memset(x, 0, sizeof(struct ", + className, + "));", + ); + const recur = (type: Type, level: number) => { + if (type instanceof ArrayType) { + const child_level = level + 1; + const cJSON = this.quicktypeTypeToCJSON( + type.items, + false, + ); + this.emitLine( + "list_t * x", + child_level.toString(), + " = list_create(false, NULL);", + ); this.emitBlock( - ["cJSON_ArrayForEach(e", child_level.toString(), ", e", level.toString(), ")"], + [ + "if (NULL != x", + child_level.toString(), + ")", + ], () => { - if (cJSON.cjsonType === "cJSON_Array") { - const child_level2 = child_level + 1; - recur(type.items, child_level); - this.emitLine( - "list_add_tail(x", + this.emitLine( + "cJSON * e", + child_level.toString(), + " = NULL;", + ); + this.emitBlock( + [ + "cJSON_ArrayForEach(e", child_level.toString(), - ", x", - child_level2.toString(), - ", sizeof(", - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *));" - ); - } else if (cJSON.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.cjsonType === "cJSON_Invalid" || - cJSON.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", (", - cJSON.cType, - " *)0xDEADBEEF, sizeof(", - cJSON.cType, - " *));" - ); - } else if (cJSON.cjsonType === "cJSON_String") { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", strdup(", - cJSON.getValue, - "(e", - child_level.toString(), - ")), sizeof(", - cJSON.cType, - " *));" - ); - } else if ( - cJSON.cjsonType === "cJSON_Object" || - cJSON.cjsonType === "cJSON_Union" - ) { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", ", - cJSON.getValue, - "(e", - child_level.toString(), - "), sizeof(", - cJSON.cType, - " *));" - ); - } else { - this.emitLine( - cJSON.cType, - " * tmp", - level > 0 ? level.toString() : "", - " = cJSON_malloc(sizeof(", - cJSON.cType, - "));" - ); - this.emitBlock( - ["if (NULL != tmp", level > 0 ? level.toString() : "", ")"], - () => { - this.emitLine( - "* tmp", - level > 0 ? level.toString() : "", - " = ", - cJSON.getValue, - "(e", - child_level.toString(), - ");" + ", e", + level.toString(), + ")", + ], + () => { + if ( + cJSON.cjsonType === + "cJSON_Array" + ) { + const child_level2 = + child_level + 1; + recur( + type.items, + child_level, ); this.emitLine( "list_add_tail(x", child_level.toString(), - ", tmp", - level > 0 ? level.toString() : "", + ", x", + child_level2.toString(), ", sizeof(", - cJSON.cType, - " *));" + // @ts-expect-error awaiting refactor + cJSON.items?.cType, + " *));", ); - } - ); - } - } - ); - }); - } else if (type instanceof ClassType) { - this.forEachClassProperty(type, "none", (name, jsonName, property) => { - const cJSON = this.quicktypeTypeToCJSON(property.type, property.isOptional); - this.emitBlock( - !cJSON.isNullable - ? [ - "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.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { - const child_level = level + 1; - this.emitLine( - cJSON.cType, - " * x", - child_level.toString(), - " = list_create(false, NULL);" - ); - this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { - this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); - this.emitLine( - "cJSON * j", - child_level.toString(), - " = cJSON_GetObjectItemCaseSensitive(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '");' - ); - this.emitBlock( - [ - "cJSON_ArrayForEach(e", + } else if ( + cJSON.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.cjsonType === + "cJSON_Invalid" || + cJSON.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "list_add_tail(x", child_level.toString(), - ", j", + ", (", + cJSON.cType, + " *)0xDEADBEEF, sizeof(", + cJSON.cType, + " *));", + ); + } else if ( + cJSON.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "list_add_tail(x", child_level.toString(), - ")" - ], - () => { - const add = ( - type: Type, - cJSON: TypeCJSON, - level: number, - child_level: number - ) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - if (type instanceof ArrayType) { - const child_level2 = child_level + 1; - recur(type.items, child_level); - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", x", - child_level2.toString(), - ", sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - panic("Invalid type"); - } - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", (", - cJSON.items?.cType, - " *)0xDEADBEEF, sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if (cJSON.items?.cjsonType === "cJSON_String") { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", strdup(", - cJSON.items?.getValue, - "(e", - child_level.toString(), - ")), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if ( - cJSON.items?.cjsonType === "cJSON_Object" || - cJSON.items?.cjsonType === "cJSON_Union" - ) { - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", ", - cJSON.items?.getValue, - "(e", - child_level.toString(), - "), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * tmp", - level > 0 ? level.toString() : "", - " = cJSON_malloc(sizeof(", - cJSON.items?.cType, - "));" - ); - this.emitBlock( - [ - "if (NULL != tmp", - level > 0 ? level.toString() : "", - ")" - ], - () => { - this.emitLine( - "* tmp", - level > 0 ? level.toString() : "", - " = ", - // @ts-expect-error awaiting refactor - cJSON.items?.getValue, - "(e", - child_level.toString(), - ");" - ); - this.emitLine( - "list_add_tail(x", - child_level.toString(), - ", tmp", - level > 0 ? level.toString() : "", - ", sizeof(", - // @ts-expect-error awaiting refactor - 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 *));" - ); - }); - } else { - add(property.type, cJSON, level, child_level); - } - } - ); - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = x", - child_level.toString(), - ";" - ); - }); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { - const child_level = level + 1; - this.emitLine( - cJSON.cType, - " * x", - child_level.toString(), - " = hashtable_create(", - this.hashtableSize, - ", false);" - ); - this.emitBlock(["if (NULL != x", child_level.toString(), ")"], () => { - this.emitLine("cJSON * e", child_level.toString(), " = NULL;"); - this.emitLine( - "cJSON * j", - child_level.toString(), - " = cJSON_GetObjectItemCaseSensitive(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '");' - ); - this.emitBlock( - [ - "cJSON_ArrayForEach(e", + ", strdup(", + cJSON.getValue, + "(e", child_level.toString(), - ", j", + ")), sizeof(", + cJSON.cType, + " *));", + ); + } else if ( + cJSON.cjsonType === + "cJSON_Object" || + cJSON.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "list_add_tail(x", child_level.toString(), - ")" - ], - () => { - const add = ( - type: Type, - cJSON: TypeCJSON, - level: number, - child_level: number - ) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - if (type instanceof MapType) { - const child_level2 = child_level + 1; - recur(type.values, child_level); - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, x", - child_level2.toString(), - ", sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - panic("Invalid type"); - } - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, (", - cJSON.items?.cType, - " *)0xDEADBEEF, sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if (cJSON.items?.cjsonType === "cJSON_String") { - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, strdup(", - cJSON.items?.getValue, - "(e", - child_level.toString(), - ")), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if ( - cJSON.items?.cjsonType === "cJSON_Object" || - cJSON.items?.cjsonType === "cJSON_Union" - ) { - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, ", - cJSON.items?.getValue, - "(e", - child_level.toString(), - "), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * tmp", - level > 0 ? level.toString() : "", - " = cJSON_malloc(sizeof(", - cJSON.items?.cType, - "));" - ); - this.emitBlock( - [ - "if (NULL != tmp", - level > 0 ? level.toString() : "", - ")" - ], - () => { - this.emitLine( - "* tmp", - level > 0 ? level.toString() : "", - " = ", - // @ts-expect-error awaiting refactor - cJSON.items?.getValue, - "(e", - child_level.toString(), - ");" - ); - this.emitLine( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, tmp", - level > 0 ? level.toString() : "", - ", sizeof(", - // @ts-expect-error awaiting refactor - 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( - "hashtable_add(x", - child_level.toString(), - ", e", - child_level.toString(), - "->string, (void *)0xDEADBEEF, sizeof(void *));" - ); - }); - } else { - add(property.type, cJSON, level, child_level); - } - } - ); - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = x", - child_level.toString(), - ";" - ); - }); - } else if ( - cJSON.cjsonType === "cJSON_Invalid" || - cJSON.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = (", - cJSON.cType, - " *)0xDEADBEEF;" - ); - } else if (cJSON.cjsonType === "cJSON_String") { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = strdup(", - cJSON.getValue, - "(cJSON_GetObjectItemCaseSensitive(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '")));' - ); - } else if ( - cJSON.cjsonType === "cJSON_Object" || - cJSON.cjsonType === "cJSON_Union" - ) { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = ", - cJSON.getValue, - "(cJSON_GetObjectItemCaseSensitive(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '"));' - ); - } else { - if (property.isOptional || cJSON.isNullable) { - this.emitBlock( - [ - "if (NULL != (x", - level > 0 ? level.toString() : "", - "->", - name, + ", ", + cJSON.getValue, + "(e", + child_level.toString(), + "), sizeof(", + cJSON.cType, + " *));", + ); + } else { + this.emitLine( + cJSON.cType, + " * tmp", + level > 0 + ? level.toString() + : "", " = cJSON_malloc(sizeof(", cJSON.cType, - "))))" - ], - () => { + "));", + ); + this.emitBlock( + [ + "if (NULL != tmp", + level > 0 + ? level.toString() + : "", + ")", + ], + () => { + this.emitLine( + "* tmp", + level > 0 + ? level.toString() + : "", + " = ", + cJSON.getValue, + "(e", + child_level.toString(), + ");", + ); + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", tmp", + level > 0 + ? level.toString() + : "", + ", sizeof(", + cJSON.cType, + " *));", + ); + }, + ); + } + }, + ); + }, + ); + } else if (type instanceof ClassType) { + this.forEachClassProperty( + type, + "none", + (name, jsonName, property) => { + const cJSON = + this.quicktypeTypeToCJSON( + property.type, + property.isOptional, + ); + this.emitBlock( + !cJSON.isNullable + ? [ + "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.cjsonType === + "cJSON_Array" && + cJSON.items !== + undefined + ) { + const child_level = + level + 1; + this.emitLine( + cJSON.cType, + " * x", + child_level.toString(), + " = list_create(false, NULL);", + ); + this.emitBlock( + [ + "if (NULL != x", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + "cJSON * e", + child_level.toString(), + " = NULL;", + ); + this.emitLine( + "cJSON * j", + child_level.toString(), + " = cJSON_GetObjectItemCaseSensitive(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '");', + ); + this.emitBlock( + [ + "cJSON_ArrayForEach(e", + child_level.toString(), + ", j", + child_level.toString(), + ")", + ], + () => { + const add = + ( + type: Type, + cJSON: TypeCJSON, + level: number, + child_level: number, + ) => { + if ( + cJSON + .items + ?.cjsonType === + "cJSON_Array" + ) { + if ( + type instanceof + ArrayType + ) { + const child_level2 = + child_level + + 1; + recur( + type.items, + child_level, + ); + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", x", + child_level2.toString(), + ", sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else { + panic( + "Invalid type", + ); + } + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Invalid" || + cJSON + .items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", (", + cJSON + .items + ?.cType, + " *)0xDEADBEEF, sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", strdup(", + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + ")), sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Object" || + cJSON + .items + ?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", ", + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + "), sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON + .items + ?.cType, + " * tmp", + level > + 0 + ? level.toString() + : "", + " = cJSON_malloc(sizeof(", + cJSON + .items + ?.cType, + "));", + ); + this.emitBlock( + [ + "if (NULL != tmp", + level > + 0 + ? level.toString() + : "", + ")", + ], + () => { + this.emitLine( + "* tmp", + level > + 0 + ? level.toString() + : "", + " = ", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + ");", + ); + this.emitLine( + "list_add_tail(x", + child_level.toString(), + ", tmp", + level > + 0 + ? level.toString() + : "", + ", sizeof(", + // @ts-expect-error awaiting refactor + 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 *));", + ); + }, + ); + } else { + add( + property.type, + cJSON, + level, + child_level, + ); + } + }, + ); + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = x", + child_level.toString(), + ";", + ); + }, + ); + } else if ( + cJSON.cjsonType === + "cJSON_Map" && + cJSON.items !== + undefined + ) { + const child_level = + level + 1; + this.emitLine( + cJSON.cType, + " * x", + child_level.toString(), + " = hashtable_create(", + this.hashtableSize, + ", false);", + ); + this.emitBlock( + [ + "if (NULL != x", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + "cJSON * e", + child_level.toString(), + " = NULL;", + ); + this.emitLine( + "cJSON * j", + child_level.toString(), + " = cJSON_GetObjectItemCaseSensitive(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '");', + ); + this.emitBlock( + [ + "cJSON_ArrayForEach(e", + child_level.toString(), + ", j", + child_level.toString(), + ")", + ], + () => { + const add = + ( + type: Type, + cJSON: TypeCJSON, + level: number, + child_level: number, + ) => { + if ( + cJSON + .items + ?.cjsonType === + "cJSON_Array" + ) { + if ( + type instanceof + MapType + ) { + const child_level2 = + child_level + + 1; + recur( + type.values, + child_level, + ); + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, x", + child_level2.toString(), + ", sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else { + panic( + "Invalid type", + ); + } + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Invalid" || + cJSON + .items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, (", + cJSON + .items + ?.cType, + " *)0xDEADBEEF, sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, strdup(", + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + ")), sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Object" || + cJSON + .items + ?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, ", + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + "), sizeof(", + cJSON + .items + ?.cType, + " *));", + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON + .items + ?.cType, + " * tmp", + level > + 0 + ? level.toString() + : "", + " = cJSON_malloc(sizeof(", + cJSON + .items + ?.cType, + "));", + ); + this.emitBlock( + [ + "if (NULL != tmp", + level > + 0 + ? level.toString() + : "", + ")", + ], + () => { + this.emitLine( + "* tmp", + level > + 0 + ? level.toString() + : "", + " = ", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.getValue, + "(e", + child_level.toString(), + ");", + ); + this.emitLine( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, tmp", + level > + 0 + ? level.toString() + : "", + ", sizeof(", + // @ts-expect-error awaiting refactor + 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( + "hashtable_add(x", + child_level.toString(), + ", e", + child_level.toString(), + "->string, (void *)0xDEADBEEF, sizeof(void *));", + ); + }, + ); + } else { + add( + property.type, + cJSON, + level, + child_level, + ); + } + }, + ); + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = x", + child_level.toString(), + ";", + ); + }, + ); + } else if ( + cJSON.cjsonType === + "cJSON_Invalid" || + cJSON.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = (", + cJSON.cType, + " *)0xDEADBEEF;", + ); + } else if ( + cJSON.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = strdup(", + cJSON.getValue, + "(cJSON_GetObjectItemCaseSensitive(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '")));', + ); + } else if ( + cJSON.cjsonType === + "cJSON_Object" || + cJSON.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = ", + cJSON.getValue, + "(cJSON_GetObjectItemCaseSensitive(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '"));', + ); + } else { + if ( + property.isOptional || + cJSON.isNullable + ) { + this.emitBlock( + [ + "if (NULL != (x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = cJSON_malloc(sizeof(", + cJSON.cType, + "))))", + ], + () => { + this.emitLine( + "*x", + level > + 0 + ? level.toString() + : "", + "->", + name, + " = ", + cJSON.getValue, + "(cJSON_GetObjectItemCaseSensitive(j", + level > + 0 + ? level.toString() + : "", + ', "', + jsonName, + '"));', + ); + }, + ); + } else { this.emitLine( - "*x", - level > 0 ? level.toString() : "", + "x", + level > 0 + ? level.toString() + : "", "->", name, " = ", cJSON.getValue, "(cJSON_GetObjectItemCaseSensitive(j", - level > 0 ? level.toString() : "", + level > 0 + ? level.toString() + : "", ', "', jsonName, - '"));' + '"));', ); } + } + }, + ); + if ( + !property.isOptional && + !cJSON.isNullable + ) { + if ( + cJSON.cjsonType === + "cJSON_Array" + ) { + this.emitBlock( + ["else"], + () => { + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = list_create(false, NULL);", + ); + }, + ); + } else if ( + cJSON.cjsonType === + "cJSON_Map" + ) { + this.emitBlock( + ["else"], + () => { + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = hashtable_create(", + this + .hashtableSize, + ", false);", + ); + }, + ); + } else if ( + cJSON.cjsonType === + "cJSON_Invalid" || + cJSON.cjsonType === + "cJSON_NULL" + ) { + this.emitBlock( + ["else"], + () => { + this.emitLine( + "x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = (", + cJSON.cType, + " *)0xDEADBEEF;", + ); + }, + ); + } else if ( + cJSON.cjsonType === + "cJSON_String" + ) { + this.emitBlock( + ["else"], + () => { + this.emitBlock( + [ + "if (NULL != (x", + level > 0 + ? level.toString() + : "", + "->", + name, + " = cJSON_malloc(sizeof(", + cJSON.cType, + "))))", + ], + () => { + this.emitLine( + "x", + level > + 0 + ? level.toString() + : "", + "->", + name, + "[0] = '\\0';", + ); + }, + ); + }, ); } else { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = ", - cJSON.getValue, - "(cJSON_GetObjectItemCaseSensitive(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '"));' - ); + /* Nothing to do */ } } - } + }, ); - if (!property.isOptional && !cJSON.isNullable) { - if (cJSON.cjsonType === "cJSON_Array") { - this.emitBlock(["else"], () => { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = list_create(false, NULL);" - ); - }); - } else if (cJSON.cjsonType === "cJSON_Map") { - this.emitBlock(["else"], () => { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = hashtable_create(", - this.hashtableSize, - ", false);" - ); - }); - } else if ( - cJSON.cjsonType === "cJSON_Invalid" || - cJSON.cjsonType === "cJSON_NULL" - ) { - this.emitBlock(["else"], () => { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - " = (", - cJSON.cType, - " *)0xDEADBEEF;" - ); - }); - } else if (cJSON.cjsonType === "cJSON_String") { - this.emitBlock(["else"], () => { - this.emitBlock( - [ - "if (NULL != (x", - level > 0 ? level.toString() : "", - "->", - name, - " = cJSON_malloc(sizeof(", - cJSON.cType, - "))))" - ], - () => { - this.emitLine( - "x", - level > 0 ? level.toString() : "", - "->", - name, - "[0] = '\\0';" - ); - } - ); - }); - } else { - /* Nothing to do */ - } - } - }); - } - }; + } + }; - recur(classType, 0); - }); + recur(classType, 0); + }, + ); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); /* Create className to cJSON generator function */ this.emitBlock( - ["cJSON * cJSON_Create", className, "(", this.withConst(["struct ", className]), " * x)"], + [ + "cJSON * cJSON_Create", + className, + "(", + this.withConst(["struct ", className]), + " * x)", + ], () => { this.emitLine("cJSON * j = NULL;"); this.emitBlock(["if (NULL != x)"], () => { - this.emitBlock(["if (NULL != (j = cJSON_CreateObject()))"], () => { - const recur = (type: Type, level: number) => { - if (type instanceof ArrayType) { - const child_level = level + 1; - const cJSON = this.quicktypeTypeToCJSON(type.items, false); - this.emitLine("cJSON * j", child_level.toString(), " = cJSON_CreateArray();"); - this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { - this.emitLine( - cJSON.cType, - " * x", - child_level.toString(), - " = list_get_head(x", - level.toString(), - ");" + this.emitBlock( + ["if (NULL != (j = cJSON_CreateObject()))"], + () => { + const recur = (type: Type, level: number) => { + if (type instanceof ArrayType) { + const child_level = level + 1; + const cJSON = this.quicktypeTypeToCJSON( + type.items, + false, ); - this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.cjsonType === "cJSON_Array") { - const child_level2 = child_level + 1; - recur(type.items, child_level); - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", j", - child_level2.toString(), - ");" - ); - } else if (cJSON.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if (cJSON.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.cjsonType === "cJSON_NULL") { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", ", - cJSON.createObject, - "());" - ); - } else if ( - cJSON.cjsonType === "cJSON_String" || - cJSON.cjsonType === "cJSON_Object" || - cJSON.cjsonType === "cJSON_Union" - ) { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", ", - cJSON.createObject, - "(x", - child_level.toString(), - "));" - ); - } else { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", ", - cJSON.createObject, - "(*x", - child_level.toString(), - "));" - ); - } - - this.emitLine( - "x", + this.emitLine( + "cJSON * j", + child_level.toString(), + " = cJSON_CreateArray();", + ); + this.emitBlock( + [ + "if (NULL != j", child_level.toString(), - " = list_get_next(x", - level.toString(), - ");" - ); - }); - }); - } else if (type instanceof ClassType) { - this.forEachClassProperty(type, "none", (name, jsonName, property) => { - const cJSON = this.quicktypeTypeToCJSON(property.type, property.isOptional); - if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { - const child_level = level + 1; - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine( - "cJSON * j", + ")", + ], + () => { + this.emitLine( + cJSON.cType, + " * x", + child_level.toString(), + " = list_get_head(x", + level.toString(), + ");", + ); + this.emitBlock( + [ + "while (NULL != x", child_level.toString(), - " = cJSON_AddArrayToObject(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '");' - ); - this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { + ")", + ], + () => { + if ( + cJSON.cjsonType === + "cJSON_Array" + ) { + const child_level2 = + child_level + 1; + recur( + type.items, + child_level, + ); + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", j", + child_level2.toString(), + ");", + ); + } else if ( + cJSON.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", ", + cJSON.createObject, + "());", + ); + } else if ( + cJSON.cjsonType === + "cJSON_String" || + cJSON.cjsonType === + "cJSON_Object" || + cJSON.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", ", + cJSON.createObject, + "(x", + child_level.toString(), + "));", + ); + } else { + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", ", + cJSON.createObject, + "(*x", + child_level.toString(), + "));", + ); + } + this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * x", + "x", child_level.toString(), - " = list_get_head(x", - level > 0 ? level.toString() : "", + " = list_get_next(x", + level.toString(), + ");", + ); + }, + ); + }, + ); + } else if (type instanceof ClassType) { + this.forEachClassProperty( + type, + "none", + (name, jsonName, property) => { + const cJSON = + this.quicktypeTypeToCJSON( + property.type, + property.isOptional, + ); + if ( + cJSON.cjsonType === + "cJSON_Array" && + cJSON.items !== undefined + ) { + const child_level = level + 1; + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", "->", name, - ");" - ); - this.emitBlock( - ["while (NULL != x", child_level.toString(), ")"], - () => { - const add = ( - type: Type, - cJSON: TypeCJSON, - child_level: number - ) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - if (type instanceof ArrayType) { - const child_level2 = child_level + 1; - recur(type.items, child_level); - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", j", - child_level2.toString(), - ");" - ); - } else { - panic("Invalid type"); - } - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.items?.cjsonType === "cJSON_NULL") { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", ", - cJSON.items?.createObject, - "());" - ); - } else if ( - 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, - "(x", - child_level.toString(), - "));" - ); - } else { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", ", - // @ts-expect-error awaiting refactor - cJSON.items?.createObject, - "(*x", - child_level.toString(), - "));" - ); - } - }; - - if (cJSON.items?.isNullable) { + ")", + ], + () => { + this.emitLine( + "cJSON * j", + child_level.toString(), + " = cJSON_AddArrayToObject(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '");', + ); + this.emitBlock( + [ + "if (NULL != j", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items + ?.cType, + " * x", + child_level.toString(), + " = list_get_head(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); this.emitBlock( [ - "if ((void *)0xDEADBEEF != x", + "while (NULL != x", child_level.toString(), - ")" + ")", ], () => { - add(property.type, cJSON, child_level); - } - ); - this.emitBlock(["else"], () => { - this.emitLine( - "cJSON_AddItemToArray(j", - child_level.toString(), - ", cJSON_CreateNull());" - ); - }); - } else { - add(property.type, cJSON, child_level); - } + const add = + ( + type: Type, + cJSON: TypeCJSON, + child_level: number, + ) => { + if ( + cJSON + .items + ?.cjsonType === + "cJSON_Array" + ) { + if ( + type instanceof + ArrayType + ) { + const child_level2 = + child_level + + 1; + recur( + type.items, + child_level, + ); + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", j", + child_level2.toString(), + ");", + ); + } else { + panic( + "Invalid type", + ); + } + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", ", + cJSON + .items + ?.createObject, + "());", + ); + } else if ( + 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, + "(x", + child_level.toString(), + "));", + ); + } else { + this.emitLine( + "cJSON_AddItemToArray(j", + child_level.toString(), + ", ", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.createObject, + "(*x", + child_level.toString(), + "));", + ); + } + }; - this.emitLine( - "x", - child_level.toString(), - " = list_get_next(x", - level > 0 ? level.toString() : "", - "->", - name, - ");" - ); - } - ); - }); - } - ); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { - const child_level = level + 1; - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine( - "cJSON * j", - child_level.toString(), - " = ", - cJSON.createObject, - "();" + 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());", + ); + }, + ); + } else { + add( + property.type, + cJSON, + child_level, + ); + } + + this.emitLine( + "x", + child_level.toString(), + " = list_get_next(x", + level > + 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + }, + ); + }, + ); + }, ); - this.emitBlock(["if (NULL != j", child_level.toString(), ")"], () => { - this.emitLine("char **keys", child_level.toString(), " = NULL;"); - this.emitLine( - "size_t count", - child_level.toString(), - " = hashtable_get_keys(x", - level > 0 ? level.toString() : "", + } else if ( + cJSON.cjsonType === + "cJSON_Map" && + cJSON.items !== undefined + ) { + const child_level = level + 1; + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", "->", name, - ", &keys", - child_level.toString(), - ");" - ); - this.emitBlock( - ["if (NULL != keys", child_level.toString(), ")"], - () => { - this.emitBlock( - [ - "for (size_t index", + ")", + ], + () => { + this.emitLine( + "cJSON * j", + child_level.toString(), + " = ", + cJSON.createObject, + "();", + ); + this.emitBlock( + [ + "if (NULL != j", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + "char **keys", child_level.toString(), - " = 0; index", + " = NULL;", + ); + this.emitLine( + "size_t count", child_level.toString(), - " < count", + " = hashtable_get_keys(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ", &keys", child_level.toString(), - "; index", - child_level.toString(), - "++)" - ], - () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *x", + ");", + ); + this.emitBlock( + [ + "if (NULL != keys", child_level.toString(), - " = hashtable_lookup(x", - level > 0 ? level.toString() : "", - "->", - name, - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "]);" - ); - const add = ( - type: Type, - cJSON: TypeCJSON, - child_level: number - ) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - if (type instanceof MapType) { - const child_level2 = child_level + 1; - recur(type.values, child_level); + ")", + ], + () => { + this.emitBlock( + [ + "for (size_t index", + child_level.toString(), + " = 0; index", + child_level.toString(), + " < count", + child_level.toString(), + "; index", + child_level.toString(), + "++)", + ], + () => { this.emitLine( - cJSON.addToObject, - "(j", + // @ts-expect-error awaiting refactor + cJSON + .items + ?.cType, + " *x", child_level.toString(), + " = hashtable_lookup(x", + level > + 0 + ? level.toString() + : "", + "->", + name, ", keys", child_level.toString(), "[index", child_level.toString(), - "], j", - child_level2.toString(), - ");" + "]);", ); - } else { - panic("Invalid type"); - } - } else if ( - cJSON.items?.cjsonType === "cJSON_Map" - ) { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" - ) { - /* Nothing to do */ - } else if ( - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - cJSON.addToObject, - "(j", - child_level.toString(), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "], ", - cJSON.items?.createObject, - "());" - ); - } else if ( - cJSON.items?.cjsonType === "cJSON_String" || - cJSON.items?.cjsonType === "cJSON_Object" || - cJSON.items?.cjsonType === "cJSON_Union" - ) { - this.emitLine( - cJSON.addToObject, - "(j", - child_level.toString(), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "], ", - cJSON.items?.createObject, - "(x", - child_level.toString(), - "));" - ); - } else { - this.emitLine( - cJSON.addToObject, - "(j", - child_level.toString(), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "], ", - // @ts-expect-error awaiting refactor - cJSON.items?.createObject, - "(*x", - child_level.toString(), - "));" - ); - } - }; + const add = + ( + type: Type, + cJSON: TypeCJSON, + child_level: number, + ) => { + if ( + cJSON + .items + ?.cjsonType === + "cJSON_Array" + ) { + if ( + type instanceof + MapType + ) { + const child_level2 = + child_level + + 1; + recur( + type.values, + child_level, + ); + this.emitLine( + cJSON.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], j", + child_level2.toString(), + ");", + ); + } else { + panic( + "Invalid type", + ); + } + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + cJSON.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], ", + cJSON + .items + ?.createObject, + "());", + ); + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_String" || + cJSON + .items + ?.cjsonType === + "cJSON_Object" || + cJSON + .items + ?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + cJSON.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], ", + cJSON + .items + ?.createObject, + "(x", + child_level.toString(), + "));", + ); + } else { + this.emitLine( + cJSON.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], ", + // @ts-expect-error awaiting refactor + 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); - } + 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.addToObject, + "(j", + child_level.toString(), + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "], cJSON_CreateNull());", + ); + }, + ); + } else { + add( + property.type, + cJSON, + child_level, + ); + } + }, ); - this.emitBlock(["else"], () => { - this.emitLine( - cJSON.addToObject, - "(j", - child_level.toString(), - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "], 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', + child_level.toString(), + ");", + ); + }, + ); + }, + ); + } else if ( + cJSON.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON.cjsonType === "cJSON_NULL" + ) { + if (property.isOptional) { + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { this.emitLine( - "cJSON_free(keys", - child_level.toString(), - ");" + cJSON.addToObject, + "(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '");', ); - } + }, ); + } else { this.emitLine( cJSON.addToObject, "(j", - level > 0 ? level.toString() : "", + level > 0 + ? level.toString() + : "", ', "', jsonName, - '", j', - child_level.toString(), - ");" - ); - }); - } - ); - } else if (cJSON.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.cjsonType === "cJSON_NULL") { - if (property.isOptional) { - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine( - 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") { - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine( - cJSON.addToObject, - "(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '", x', - level > 0 ? level.toString() : "", - "->", - name, - ");" + } else if ( + cJSON.cjsonType === + "cJSON_String" + ) { + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { + this.emitLine( + cJSON.addToObject, + "(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '", x', + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + }, ); - } - ); - if (!property.isOptional && !cJSON.isNullable) { - this.emitBlock(["else"], () => { - this.emitLine( - cJSON.addToObject, - "(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '", "");' - ); - }); - } - } else if ( - cJSON.cjsonType === "cJSON_Object" || - cJSON.cjsonType === "cJSON_Union" - ) { - if (property.isOptional || cJSON.isNullable) { - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { + if ( + !property.isOptional && + !cJSON.isNullable + ) { + this.emitBlock( + ["else"], + () => { + this.emitLine( + cJSON.addToObject, + "(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '", "");', + ); + }, + ); + } + } else if ( + cJSON.cjsonType === + "cJSON_Object" || + cJSON.cjsonType === + "cJSON_Union" + ) { + if ( + property.isOptional || + cJSON.isNullable + ) { + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { + this.emitLine( + 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() : "", + level > 0 + ? level.toString() + : "", ', "', jsonName, '", ', cJSON.createObject, "(x", - level > 0 ? level.toString() : "", + 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") { - if (property.isOptional || cJSON.isNullable) { - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { + } else if ( + cJSON.cjsonType === "cJSON_Enum" + ) { + if ( + property.isOptional || + cJSON.isNullable + ) { + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { + this.emitLine( + 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() : "", + level > 0 + ? level.toString() + : "", ', "', jsonName, '", ', cJSON.createObject, - "(*x", - level > 0 ? level.toString() : "", + "(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 (property.isOptional || cJSON.isNullable) { - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { + } else { + if ( + property.isOptional || + cJSON.isNullable + ) { + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { + this.emitLine( + cJSON.addToObject, + "(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '", *x', + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + }, + ); + } else { this.emitLine( cJSON.addToObject, "(j", - level > 0 ? level.toString() : "", + level > 0 + ? level.toString() + : "", ', "', jsonName, - '", *x', - level > 0 ? level.toString() : "", + '", x', + level > 0 + ? level.toString() + : "", "->", name, - ");" + ");", ); } - ); - } else { - this.emitLine( - cJSON.addToObject, - "(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '", x', - level > 0 ? level.toString() : "", - "->", - name, - ");" - ); - } - } + } - if (cJSON.isNullable) { - this.emitBlock(["else"], () => { - this.emitLine( - "cJSON_AddNullToObject(j", - level > 0 ? level.toString() : "", - ', "', - jsonName, - '");' - ); - }); - } - }); - } - }; + if (cJSON.isNullable) { + this.emitBlock(["else"], () => { + this.emitLine( + "cJSON_AddNullToObject(j", + level > 0 + ? level.toString() + : "", + ', "', + jsonName, + '");', + ); + }); + } + }, + ); + } + }; - recur(classType, 0); - }); + recur(classType, 0); + }, + ); }); this.emitLine("return j;"); - } + }, ); this.ensureBlankLine(); /* Create className to string generator function */ - this.emitBlock(["char * cJSON_Print", className, "(", this.withConst(["struct ", className]), " * x)"], () => { - this.emitLine("char * s = NULL;"); - this.emitBlock(["if (NULL != x)"], () => { - this.emitLine("cJSON * j = cJSON_Create", className, "(x);"); - this.emitBlock(["if (NULL != j)"], () => { - this.emitLine(this._options.printStyle ? "s = cJSON_PrintUnformatted(j);" : "s = cJSON_Print(j);"); - this.emitLine("cJSON_Delete(j);"); + this.emitBlock( + [ + "char * cJSON_Print", + className, + "(", + this.withConst(["struct ", className]), + " * x)", + ], + () => { + this.emitLine("char * s = NULL;"); + this.emitBlock(["if (NULL != x)"], () => { + this.emitLine( + "cJSON * j = cJSON_Create", + className, + "(x);", + ); + this.emitBlock(["if (NULL != j)"], () => { + this.emitLine( + this._options.printStyle + ? "s = cJSON_PrintUnformatted(j);" + : "s = cJSON_Print(j);", + ); + this.emitLine("cJSON_Delete(j);"); + }); }); - }); - this.emitLine("return s;"); - }); + this.emitLine("return s;"); + }, + ); this.ensureBlankLine(); /* Create className delete function */ - this.emitBlock(["void cJSON_Delete", className, "(struct ", className, " * x)"], () => { - this.emitBlock(["if (NULL != x)"], () => { - const recur = (type: Type, level: number) => { - if (type instanceof ArrayType) { - const child_level = level + 1; - const cJSON = this.quicktypeTypeToCJSON(type.items, false); - this.emitLine( - cJSON.cType, - " * x", - child_level.toString(), - " = list_get_head(x", - level.toString(), - ");" - ); - this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.cjsonType === "cJSON_Array") { - recur(type.items, child_level); - this.emitLine(cJSON.deleteType, "(x", child_level.toString(), ");"); - } else if (cJSON.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { - /* Nothing to do */ - } 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) { - this.forEachClassProperty(type, "none", (name, _jsonName, property) => { - const cJSON = this.quicktypeTypeToCJSON(property.type, property.isOptional); - if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { - const child_level = level + 1; - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " * x", - child_level.toString(), - " = list_get_head(x", - level > 0 ? level.toString() : "", - "->", - name, - ");" - ); - this.emitBlock(["while (NULL != x", child_level.toString(), ")"], () => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - if (property.type instanceof ArrayType) { - recur(property.type.items, child_level); - this.emitLine( - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } else { - panic("Invalid type"); - } - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - /* Nothing to do */ - } else { - if (cJSON.items?.isNullable) { - this.emitBlock( - ["if ((void *)0xDEADBEEF != x", child_level.toString(), ")"], - () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } - ); - } else { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } - } - - this.emitLine( - "x", - child_level.toString(), - " = list_get_next(x", - level > 0 ? level.toString() : "", - "->", - name, - ");" - ); - }); + this.emitBlock( + ["void cJSON_Delete", className, "(struct ", className, " * x)"], + () => { + this.emitBlock(["if (NULL != x)"], () => { + const recur = (type: Type, level: number) => { + if (type instanceof ArrayType) { + const child_level = level + 1; + const cJSON = this.quicktypeTypeToCJSON( + type.items, + false, + ); + this.emitLine( + cJSON.cType, + " * x", + child_level.toString(), + " = list_get_head(x", + level.toString(), + ");", + ); + this.emitBlock( + [ + "while (NULL != x", + child_level.toString(), + ")", + ], + () => { + if (cJSON.cjsonType === "cJSON_Array") { + recur(type.items, child_level); this.emitLine( cJSON.deleteType, "(x", - level > 0 ? level.toString() : "", - "->", - name, - ");" + child_level.toString(), + ");", + ); + } else if ( + cJSON.cjsonType === "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.cjsonType === "cJSON_Invalid" || + cJSON.cjsonType === "cJSON_NULL" + ) { + /* Nothing to do */ + } else { + this.emitLine( + cJSON.deleteType, + "(x", + child_level.toString(), + ");", ); } - ); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { - const child_level = level + 1; - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine("char **keys", child_level.toString(), " = NULL;"); - this.emitLine( - "size_t count", - child_level.toString(), - " = hashtable_get_keys(x", - level > 0 ? level.toString() : "", - "->", - name, - ", &keys", - child_level.toString(), - ");" + + this.emitLine( + "x", + child_level.toString(), + " = list_get_next(x", + level.toString(), + ");", + ); + }, + ); + } else if (type instanceof ClassType) { + this.forEachClassProperty( + type, + "none", + (name, _jsonName, property) => { + const cJSON = this.quicktypeTypeToCJSON( + property.type, + property.isOptional, + ); + if ( + cJSON.cjsonType === "cJSON_Array" && + cJSON.items !== undefined + ) { + const child_level = level + 1; + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items?.cType, + " * x", + child_level.toString(), + " = list_get_head(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + this.emitBlock( + [ + "while (NULL != x", + child_level.toString(), + ")", + ], + () => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { + if ( + property.type instanceof + ArrayType + ) { + recur( + property + .type + .items, + child_level, + ); + this.emitLine( + cJSON.items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + } else { + panic( + "Invalid type", + ); + } + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Invalid" || + cJSON.items + ?.cjsonType === + "cJSON_NULL" + ) { + /* Nothing to do */ + } else { + if ( + cJSON.items + ?.isNullable + ) { + this.emitBlock( + [ + "if ((void *)0xDEADBEEF != x", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON + .items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + }, + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + } + } + + this.emitLine( + "x", + child_level.toString(), + " = list_get_next(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + }, + ); + this.emitLine( + cJSON.deleteType, + "(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + }, ); - this.emitBlock(["if (NULL != keys", child_level.toString(), ")"], () => { + } else if ( + cJSON.cjsonType === "cJSON_Map" && + cJSON.items !== undefined + ) { + const child_level = level + 1; + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { + this.emitLine( + "char **keys", + child_level.toString(), + " = NULL;", + ); + this.emitLine( + "size_t count", + child_level.toString(), + " = hashtable_get_keys(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ", &keys", + child_level.toString(), + ");", + ); + this.emitBlock( + [ + "if (NULL != keys", + child_level.toString(), + ")", + ], + () => { + this.emitBlock( + [ + "for (size_t index", + child_level.toString(), + " = 0; index", + child_level.toString(), + " < count", + child_level.toString(), + "; index", + child_level.toString(), + "++)", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items + ?.cType, + " *x", + child_level.toString(), + " = hashtable_lookup(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ", keys", + child_level.toString(), + "[index", + child_level.toString(), + "]);", + ); + this.emitBlock( + [ + "if (NULL != x", + child_level.toString(), + ")", + ], + () => { + if ( + cJSON + .items + ?.cjsonType === + "cJSON_Array" + ) { + if ( + property.type instanceof + MapType + ) { + recur( + property + .type + .values, + child_level, + ); + this.emitLine( + cJSON + .items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + } else { + panic( + "Invalid type", + ); + } + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON + .items + ?.cjsonType === + "cJSON_Invalid" || + cJSON + .items + ?.cjsonType === + "cJSON_NULL" + ) { + /* Nothing to do */ + } else { + if ( + cJSON + .items + ?.isNullable + ) { + this.emitBlock( + [ + "if ((void *)0xDEADBEEF != x", + child_level.toString(), + ")", + ], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON + .items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + }, + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON + .items + ?.deleteType, + "(x", + child_level.toString(), + ");", + ); + } + } + }, + ); + }, + ); + this.emitLine( + "cJSON_free(keys", + child_level.toString(), + ");", + ); + }, + ); + this.emitLine( + cJSON.deleteType, + "(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Invalid" || + cJSON.cjsonType === "cJSON_NULL" + ) { + /* Nothing to do */ + } else if ( + cJSON.cjsonType === "cJSON_String" || + cJSON.cjsonType === "cJSON_Object" || + cJSON.cjsonType === "cJSON_Union" + ) { + this.emitBlock( + [ + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", + ], + () => { + this.emitLine( + cJSON.deleteType, + "(x", + level > 0 + ? level.toString() + : "", + "->", + name, + ");", + ); + }, + ); + } else { + if ( + property.isOptional || + cJSON.isNullable + ) { this.emitBlock( [ - "for (size_t index", - child_level.toString(), - " = 0; index", - child_level.toString(), - " < count", - child_level.toString(), - "; index", - child_level.toString(), - "++)" + "if (NULL != x", + level > 0 + ? level.toString() + : "", + "->", + name, + ")", ], () => { this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *x", - child_level.toString(), - " = hashtable_lookup(x", - level > 0 ? level.toString() : "", + cJSON.deleteType, + "(x", + level > 0 + ? level.toString() + : "", "->", name, - ", keys", - child_level.toString(), - "[index", - child_level.toString(), - "]);" + ");", ); - this.emitBlock( - ["if (NULL != x", child_level.toString(), ")"], - () => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - if (property.type instanceof MapType) { - recur(property.type.values, child_level); - this.emitLine( - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } else { - panic("Invalid type"); - } - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - /* Nothing to do */ - } else { - if (cJSON.items?.isNullable) { - this.emitBlock( - [ - "if ((void *)0xDEADBEEF != x", - child_level.toString(), - ")" - ], - () => { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } - ); - } else { - this.emitLine( - // @ts-expect-error awaiting refactor - cJSON.items?.deleteType, - "(x", - child_level.toString(), - ");" - ); - } - } - } - ); - } - ); - this.emitLine("cJSON_free(keys", child_level.toString(), ");"); - }); - this.emitLine( - cJSON.deleteType, - "(x", - level > 0 ? level.toString() : "", - "->", - name, - ");" - ); - } - ); - } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { - /* Nothing to do */ - } else if ( - cJSON.cjsonType === "cJSON_String" || - cJSON.cjsonType === "cJSON_Object" || - cJSON.cjsonType === "cJSON_Union" - ) { - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine( - cJSON.deleteType, - "(x", - level > 0 ? level.toString() : "", - "->", - name, - ");" - ); - } - ); - } else { - if (property.isOptional || cJSON.isNullable) { - this.emitBlock( - ["if (NULL != x", level > 0 ? level.toString() : "", "->", name, ")"], - () => { - this.emitLine( - cJSON.deleteType, - "(x", - level > 0 ? level.toString() : "", - "->", - name, - ");" + }, ); } - ); - } - } - }); - } - }; + } + }, + ); + } + }; - recur(classType, 0); - this.emitLine("cJSON_free(x);"); - }); - }); + recur(classType, 0); + this.emitLine("cJSON_free(x);"); + }); + }, + ); this.ensureBlankLine(); } @@ -2947,13 +4610,17 @@ 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); /* Create includes - This create too much includes but this is safer because of specific corner cases */ - includes.forEach(name => { + includes.forEach((name) => { this.emitIncludeLine(name); }); this.ensureBlankLine(); @@ -2985,11 +4652,11 @@ export class CJSONRenderer extends ConvenienceRenderer { cJSON.cType, cJSON.optionalQualifier !== "" ? " " : "", cJSON.optionalQualifier, - " value;" + " value;", ); }, "", - true + true, ); this.ensureBlankLine(); this.emitTypedefAlias(type, className); @@ -3001,11 +4668,45 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param className: top level class name */ 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);"); - this.emitLine("char * cJSON_Print", className, "(", this.withConst(["struct ", className]), " * x);"); - this.emitLine("void cJSON_Delete", className, "(struct ", className, " * x);"); + 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);", + ); + this.emitLine( + "char * cJSON_Print", + className, + "(", + this.withConst(["struct ", className]), + " * x);", + ); + this.emitLine( + "void cJSON_Delete", + className, + "(struct ", + className, + " * x);", + ); this.ensureBlankLine(); } @@ -3017,7 +4718,15 @@ export class CJSONRenderer extends ConvenienceRenderer { protected emitTopLevelFunctions(type: Type, className: Name): void { /* Create string to className generator function */ this.emitBlock( - ["struct ", className, " * cJSON_Parse", className, "(", this.withConst("char"), " * s)"], + [ + "struct ", + className, + " * cJSON_Parse", + className, + "(", + this.withConst("char"), + " * s)", + ], () => { this.emitLine("struct ", className, " * x = NULL;"); this.emitBlock(["if (NULL != s)"], () => { @@ -3028,270 +4737,451 @@ export class CJSONRenderer extends ConvenienceRenderer { }); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); /* Create cJSON to className generator function */ this.emitBlock( - ["struct ", className, " * cJSON_Get", className, "Value(", this.withConst("cJSON"), " * j)"], + [ + "struct ", + className, + " * cJSON_Get", + className, + "Value(", + this.withConst("cJSON"), + " * j)", + ], () => { this.emitLine("struct ", className, " * x = NULL;"); this.emitBlock(["if (NULL != j)"], () => { - this.emitBlock(["if (NULL != (x = cJSON_malloc(sizeof(struct ", className, "))))"], () => { - this.emitLine("memset(x, 0, sizeof(struct ", className, "));"); - const cJSON = this.quicktypeTypeToCJSON(type, false); - if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { - this.emitLine("x->value = list_create(false, NULL);"); - this.emitBlock(["if (NULL != x->value)"], () => { - this.emitLine("cJSON * e = NULL;"); - this.emitBlock(["cJSON_ArrayForEach(e, j)"], () => { - const add = (cJSON: TypeCJSON) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "list_add_tail(x->value, (", - cJSON.items?.cType, - " *)0xDEADBEAF, sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if (cJSON.items?.cjsonType === "cJSON_String") { - this.emitLine( - "list_add_tail(x->value, strdup(", - cJSON.items?.getValue, - "(e)), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - this.emitLine( - "list_add_tail(x->value, ", - // @ts-expect-error awaiting refactor - cJSON.items?.getValue, - "(e), sizeof(", - cJSON.items?.cType, - " *));" - ); - } - }; + this.emitBlock( + [ + "if (NULL != (x = cJSON_malloc(sizeof(struct ", + className, + "))))", + ], + () => { + this.emitLine( + "memset(x, 0, sizeof(struct ", + className, + "));", + ); + const cJSON = this.quicktypeTypeToCJSON( + type, + false, + ); + if ( + cJSON.cjsonType === "cJSON_Array" && + cJSON.items !== undefined + ) { + this.emitLine( + "x->value = list_create(false, NULL);", + ); + this.emitBlock( + ["if (NULL != x->value)"], + () => { + this.emitLine("cJSON * e = NULL;"); + this.emitBlock( + ["cJSON_ArrayForEach(e, j)"], + () => { + const add = ( + cJSON: TypeCJSON, + ) => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Invalid" || + cJSON.items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "list_add_tail(x->value, (", + cJSON.items?.cType, + " *)0xDEADBEAF, sizeof(", + cJSON.items?.cType, + " *));", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "list_add_tail(x->value, strdup(", + cJSON.items + ?.getValue, + "(e)), sizeof(", + cJSON.items?.cType, + " *));", + ); + } else { + this.emitLine( + "list_add_tail(x->value, ", + // @ts-expect-error awaiting refactor + 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 *));" - ); - }); - } else { - add(cJSON); - } - }); - }); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { - this.emitLine("x->value = hashtable_create(", this.hashtableSize, ", false);"); - this.emitBlock(["if (NULL != x->value)"], () => { - this.emitLine("cJSON * e = NULL;"); - this.emitBlock(["cJSON_ArrayForEach(e, j)"], () => { - const add = (cJSON: TypeCJSON) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if ( - cJSON.items?.cjsonType === "cJSON_Invalid" || - cJSON.items?.cjsonType === "cJSON_NULL" - ) { - this.emitLine( - "hashtable_add(x->value, e->string, (", - cJSON.items?.cType, - " *)0xDEADBEEF, sizeof(", - cJSON.items?.cType, - " *));" - ); - } else if (cJSON.items?.cjsonType === "cJSON_String") { - this.emitLine( - "hashtable_add(x->value, e->string, strdup(", - cJSON.items?.getValue, - "(e)), sizeof(", - cJSON.items?.cType, - " *));" - ); - } else { - this.emitLine( - "hashtable_add(x->value, e->string, ", - // @ts-expect-error awaiting refactor - 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 *));", + ); + }, + ); + } else { + add(cJSON); + } + }, + ); + }, + ); + } else if ( + cJSON.cjsonType === "cJSON_Map" && + cJSON.items !== undefined + ) { + this.emitLine( + "x->value = hashtable_create(", + this.hashtableSize, + ", false);", + ); + this.emitBlock( + ["if (NULL != x->value)"], + () => { + this.emitLine("cJSON * e = NULL;"); + this.emitBlock( + ["cJSON_ArrayForEach(e, j)"], + () => { + const add = ( + cJSON: TypeCJSON, + ) => { + if ( + cJSON.items + ?.cjsonType === + "cJSON_Array" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_Invalid" || + cJSON.items + ?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + "hashtable_add(x->value, e->string, (", + cJSON.items?.cType, + " *)0xDEADBEEF, sizeof(", + cJSON.items?.cType, + " *));", + ); + } else if ( + cJSON.items + ?.cjsonType === + "cJSON_String" + ) { + this.emitLine( + "hashtable_add(x->value, e->string, strdup(", + cJSON.items + ?.getValue, + "(e)), sizeof(", + cJSON.items?.cType, + " *));", + ); + } else { + this.emitLine( + "hashtable_add(x->value, e->string, ", + // @ts-expect-error awaiting refactor + 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 *));" - ); - }); - } else { - add(cJSON); - } - }); - }); - } else if (cJSON.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.cjsonType === "cJSON_NULL") { - this.emitLine("x->value = (", cJSON.cType, " *)0xDEADBEEF;"); - } else if (cJSON.cjsonType === "cJSON_String") { - this.emitLine("x->value = strdup(", cJSON.getValue, "(j));"); - } else { - this.emitLine("x->value = ", cJSON.getValue, "(j);"); - } - }); + 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 *));", + ); + }, + ); + } else { + add(cJSON); + } + }, + ); + }, + ); + } else if (cJSON.cjsonType === "cJSON_Invalid") { + /* Nothing to do */ + } else if (cJSON.cjsonType === "cJSON_NULL") { + this.emitLine( + "x->value = (", + cJSON.cType, + " *)0xDEADBEEF;", + ); + } else if (cJSON.cjsonType === "cJSON_String") { + this.emitLine( + "x->value = strdup(", + cJSON.getValue, + "(j));", + ); + } else { + this.emitLine( + "x->value = ", + cJSON.getValue, + "(j);", + ); + } + }, + ); }); this.emitLine("return x;"); - } + }, ); this.ensureBlankLine(); /* Create className to cJSON generator function */ this.emitBlock( - ["cJSON * cJSON_Create", className, "(", this.withConst(["struct ", className]), " * x)"], + [ + "cJSON * cJSON_Create", + className, + "(", + this.withConst(["struct ", className]), + " * x)", + ], () => { this.emitLine("cJSON * j = NULL;"); this.emitBlock(["if (NULL != x)"], () => { const cJSON = this.quicktypeTypeToCJSON(type, false); - if (cJSON.cjsonType === "cJSON_Array" && cJSON.items !== undefined) { + if ( + cJSON.cjsonType === "cJSON_Array" && + cJSON.items !== undefined + ) { 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.emitLine( + // @ts-expect-error awaiting refactor + 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") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.items?.cjsonType === "cJSON_NULL") { - this.emitLine( - "cJSON_AddItemToArray(j, ", - cJSON.items?.createObject, - "());" - ); } else if ( - cJSON.items?.cjsonType === "cJSON_String" || - cJSON.items?.cjsonType === "cJSON_Object" || - cJSON.items?.cjsonType === "cJSON_Union" + cJSON.items?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items?.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON.items?.cjsonType === + "cJSON_NULL" ) { this.emitLine( "cJSON_AddItemToArray(j, ", cJSON.items?.createObject, - "(x1));" + "());", + ); + } else if ( + cJSON.items?.cjsonType === + "cJSON_String" || + cJSON.items?.cjsonType === + "cJSON_Object" || + cJSON.items?.cjsonType === + "cJSON_Union" + ) { + this.emitLine( + "cJSON_AddItemToArray(j, ", + cJSON.items?.createObject, + "(x1));", ); } else { this.emitLine( "cJSON_AddItemToArray(j, ", // @ts-expect-error awaiting refactor cJSON.items?.createObject, - "(*x1));" + "(*x1));", ); } }; if (cJSON.items?.isNullable) { - this.emitBlock(["if ((void *)0xDEADBEEF != x1)"], () => { - add(cJSON); - }); + this.emitBlock( + ["if ((void *)0xDEADBEEF != x1)"], + () => { + add(cJSON); + }, + ); this.emitBlock(["else"], () => { - this.emitLine("cJSON_AddItemToArray(j, cJSON_CreateNull());"); + this.emitLine( + "cJSON_AddItemToArray(j, cJSON_CreateNull());", + ); }); } else { add(cJSON); } - this.emitLine("x1 = list_get_next(x->value);"); + this.emitLine( + "x1 = list_get_next(x->value);", + ); }); }); }); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { + } else if ( + cJSON.cjsonType === "cJSON_Map" && + cJSON.items !== undefined + ) { this.emitBlock(["if (NULL != x->value)"], () => { this.emitLine("j = ", cJSON.createObject, "();"); this.emitBlock(["if (NULL != j)"], () => { this.emitLine("char **keys = NULL;"); - this.emitLine("size_t count = hashtable_get_keys(x->value, &keys);"); + 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( - // @ts-expect-error awaiting refactor - cJSON.items?.cType, - " *x2 = hashtable_lookup(x->value, keys[index]);" - ); - const add = (cJSON: TypeCJSON) => { - if (cJSON.items?.cjsonType === "cJSON_Array") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Map") { - /* Not supported */ - } else if (cJSON.items?.cjsonType === "cJSON_Invalid") { - /* Nothing to do */ - } else if (cJSON.items?.cjsonType === "cJSON_NULL") { - this.emitLine( - cJSON.addToObject, - "(j, keys[index], ", - cJSON.items?.createObject, - "());" - ); - } else if ( - 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, - "(x2));" - ); - } else { - this.emitLine( - cJSON.addToObject, - "(j, keys[index], ", - // @ts-expect-error awaiting refactor - cJSON.items?.createObject, - "(*x2));" - ); - } - }; + 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]);", + ); + const add = (cJSON: TypeCJSON) => { + if ( + cJSON.items?.cjsonType === + "cJSON_Array" + ) { + /* Not supported */ + } else if ( + cJSON.items?.cjsonType === + "cJSON_Map" + ) { + /* Not supported */ + } else if ( + cJSON.items?.cjsonType === + "cJSON_Invalid" + ) { + /* Nothing to do */ + } else if ( + cJSON.items?.cjsonType === + "cJSON_NULL" + ) { + this.emitLine( + cJSON.addToObject, + "(j, keys[index], ", + cJSON.items + ?.createObject, + "());", + ); + } else if ( + 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, + "(x2));", + ); + } else { + this.emitLine( + cJSON.addToObject, + "(j, keys[index], ", + // @ts-expect-error awaiting refactor + cJSON.items + ?.createObject, + "(*x2));", + ); + } + }; - if (cJSON.items?.isNullable) { - this.emitBlock(["if ((void *)0xDEADBEEF != x2)"], () => { - add(cJSON); - }); - this.emitBlock(["else"], () => { - this.emitLine( - cJSON.addToObject, - "(j, keys[index], cJSON_CreateNull());" + if (cJSON.items?.isNullable) { + this.emitBlock( + [ + "if ((void *)0xDEADBEEF != x2)", + ], + () => { + add(cJSON); + }, ); - }); - } else { - add(cJSON); - } - }); + this.emitBlock(["else"], () => { + this.emitLine( + cJSON.addToObject, + "(j, keys[index], cJSON_CreateNull());", + ); + }); + } else { + add(cJSON); + } + }, + ); this.emitLine("cJSON_free(keys);"); }); }); @@ -3301,90 +5191,158 @@ export class CJSONRenderer extends ConvenienceRenderer { } else if (cJSON.cjsonType === "cJSON_NULL") { this.emitLine("j = ", cJSON.createObject, "();"); } else { - this.emitLine("j = ", cJSON.createObject, "(x->value);"); + this.emitLine( + "j = ", + cJSON.createObject, + "(x->value);", + ); } }); this.emitLine("return j;"); - } + }, ); this.ensureBlankLine(); /* Create className to string generator function */ - this.emitBlock(["char * cJSON_Print", className, "(", this.withConst(["struct ", className]), " * x)"], () => { - this.emitLine("char * s = NULL;"); - this.emitBlock(["if (NULL != x)"], () => { - this.emitLine("cJSON * j = cJSON_Create", className, "(x);"); - this.emitBlock(["if (NULL != j)"], () => { - this.emitLine("s = cJSON_Print(j);"); - this.emitLine("cJSON_Delete(j);"); + this.emitBlock( + [ + "char * cJSON_Print", + className, + "(", + this.withConst(["struct ", className]), + " * x)", + ], + () => { + this.emitLine("char * s = NULL;"); + this.emitBlock(["if (NULL != x)"], () => { + this.emitLine( + "cJSON * j = cJSON_Create", + className, + "(x);", + ); + this.emitBlock(["if (NULL != j)"], () => { + this.emitLine("s = cJSON_Print(j);"); + this.emitLine("cJSON_Delete(j);"); + }); }); - }); - this.emitLine("return s;"); - }); + this.emitLine("return s;"); + }, + ); this.ensureBlankLine(); /* Create className delete function */ - this.emitBlock(["void cJSON_Delete", className, "(struct ", className, " * x)"], () => { - this.emitBlock(["if (NULL != x)"], () => { - 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 { + this.emitBlock( + ["void cJSON_Delete", className, "(struct ", className, " * x)"], + () => { + this.emitBlock(["if (NULL != x)"], () => { + const cJSON = this.quicktypeTypeToCJSON(type, false); + if ( + cJSON.cjsonType === "cJSON_Array" && + cJSON.items !== undefined + ) { + this.emitBlock(["if (NULL != x->value)"], () => { + this.emitLine( // @ts-expect-error awaiting refactor - this.emitLine(cJSON.items?.deleteType, "(x1);"); - } - - this.emitLine("x1 = list_get_next(x->value);"); - }); - this.emitLine(cJSON.deleteType, "(x->value);"); - }); - } else if (cJSON.cjsonType === "cJSON_Map" && cJSON.items !== undefined) { - this.emitBlock(["if (NULL != x->value)"], () => { - this.emitLine("char **keys = NULL;"); - 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 { + cJSON.items?.cType, + " * x1 = list_get_head(x->value);", + ); + this.emitBlock(["while (NULL != x1)"], () => { + if (cJSON.items?.isNullable) { + this.emitBlock( + ["if ((void *)0xDEADBEEF != x1)"], + () => { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items?.deleteType, + "(x1);", + ); + }, + ); + } else { + this.emitLine( // @ts-expect-error awaiting refactor - this.emitLine(cJSON.items?.deleteType, "(x2);"); - } - }); - }); - this.emitLine("cJSON_free(keys);"); - }); - this.emitLine(cJSON.deleteType, "(x->value);"); - }); - } else if (cJSON.cjsonType === "cJSON_Invalid" || cJSON.cjsonType === "cJSON_NULL") { - /* Nothing to do */ - } else if ( - cJSON.cjsonType === "cJSON_String" || - cJSON.cjsonType === "cJSON_Object" || - cJSON.cjsonType === "cJSON_Union" - ) { - this.emitLine(cJSON.deleteType, "(x->value);"); - } else { - /* Nothing to do */ - } + cJSON.items?.deleteType, + "(x1);", + ); + } - this.emitLine("cJSON_free(x);"); - }); - }); + this.emitLine("x1 = list_get_next(x->value);"); + }); + this.emitLine(cJSON.deleteType, "(x->value);"); + }); + } else if ( + cJSON.cjsonType === "cJSON_Map" && + cJSON.items !== undefined + ) { + this.emitBlock(["if (NULL != x->value)"], () => { + this.emitLine("char **keys = NULL;"); + 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( + // @ts-expect-error awaiting refactor + 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( + // @ts-expect-error awaiting refactor + cJSON.items + ?.deleteType, + "(x2);", + ); + }, + ); + } else { + this.emitLine( + // @ts-expect-error awaiting refactor + cJSON.items?.deleteType, + "(x2);", + ); + } + }, + ); + }, + ); + this.emitLine("cJSON_free(keys);"); + }); + this.emitLine(cJSON.deleteType, "(x->value);"); + }); + } else if ( + cJSON.cjsonType === "cJSON_Invalid" || + cJSON.cjsonType === "cJSON_NULL" + ) { + /* Nothing to do */ + } else if ( + cJSON.cjsonType === "cJSON_String" || + cJSON.cjsonType === "cJSON_Object" || + cJSON.cjsonType === "cJSON_Union" + ) { + this.emitLine(cJSON.deleteType, "(x->value);"); + } else { + /* Nothing to do */ + } + + this.emitLine("cJSON_free(x);"); + }); + }, + ); this.ensureBlankLine(); } @@ -3395,11 +5353,15 @@ 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, - _anyType => { + (_anyType) => { return { cType: "void", optionalQualifier: "*", @@ -3410,10 +5372,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "", deleteType: "", items: undefined, - isNullable + isNullable, }; }, - _nullType => { + (_nullType) => { return { cType: "void", optionalQualifier: "*", @@ -3424,10 +5386,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNull", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, - _boolType => { + (_boolType) => { return { cType: "bool", optionalQualifier: isOptional === true ? "*" : "", @@ -3438,10 +5400,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateBool", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, - _integerType => { + (_integerType) => { return { cType: this.typeIntegerSize, optionalQualifier: isOptional === true ? "*" : "", @@ -3452,10 +5414,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNumber", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, - _doubleType => { + (_doubleType) => { return { cType: "double", optionalQualifier: isOptional === true ? "*" : "", @@ -3466,10 +5428,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateNumber", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, - _stringType => { + (_stringType) => { return { cType: "char", optionalQualifier: "*", @@ -3480,10 +5442,10 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateString", deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, - arrayType => { + (arrayType) => { const items = this.quicktypeTypeToCJSON(arrayType.items, false); return { cType: "list_t", @@ -3495,24 +5457,34 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateArray", deleteType: "list_release", items, - isNullable + isNullable, }; }, - classType => { + (classType) => { return { cType: ["struct ", this.nameForNamedType(classType)], optionalQualifier: "*", cjsonType: "cJSON_Object", isType: "cJSON_IsObject", - getValue: ["cJSON_Get", this.nameForNamedType(classType), "Value"], + getValue: [ + "cJSON_Get", + this.nameForNamedType(classType), + "Value", + ], addToObject: "cJSON_AddItemToObject", - createObject: ["cJSON_Create", this.nameForNamedType(classType)], - deleteType: ["cJSON_Delete", this.nameForNamedType(classType)], + createObject: [ + "cJSON_Create", + this.nameForNamedType(classType), + ], + deleteType: [ + "cJSON_Delete", + this.nameForNamedType(classType), + ], items: undefined, - isNullable + isNullable, }; }, - mapType => { + (mapType) => { const items = this.quicktypeTypeToCJSON(mapType.values, false); return { cType: "hashtable_t", @@ -3524,42 +5496,59 @@ export class CJSONRenderer extends ConvenienceRenderer { createObject: "cJSON_CreateObject", deleteType: "hashtable_release", items, - isNullable + isNullable, }; }, - enumType => { + (enumType) => { return { cType: ["enum ", this.nameForNamedType(enumType)], optionalQualifier: isOptional === true ? "*" : "", cjsonType: "cJSON_Enum", isType: "cJSON_IsString", - getValue: ["cJSON_Get", this.nameForNamedType(enumType), "Value"], + getValue: [ + "cJSON_Get", + this.nameForNamedType(enumType), + "Value", + ], addToObject: "cJSON_AddItemToObject", - createObject: ["cJSON_Create", this.nameForNamedType(enumType)], + createObject: [ + "cJSON_Create", + this.nameForNamedType(enumType), + ], deleteType: "cJSON_free", items: undefined, - isNullable + isNullable, }; }, - unionType => { + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { return this.quicktypeTypeToCJSON(nullable, true, true); - } else { - return { - cType: ["struct ", this.nameForNamedType(unionType)], - optionalQualifier: "*", - cjsonType: "cJSON_Union", - isType: "", - getValue: ["cJSON_Get", this.nameForNamedType(unionType), "Value"], - addToObject: "cJSON_AddItemToObject", - createObject: ["cJSON_Create", this.nameForNamedType(unionType)], - deleteType: ["cJSON_Delete", this.nameForNamedType(unionType)], - items: undefined, - isNullable - }; } - } + + return { + cType: ["struct ", this.nameForNamedType(unionType)], + optionalQualifier: "*", + cjsonType: "cJSON_Union", + isType: "", + getValue: [ + "cJSON_Get", + this.nameForNamedType(unionType), + "Value", + ], + addToObject: "cJSON_AddItemToObject", + createObject: [ + "cJSON_Create", + this.nameForNamedType(unionType), + ], + deleteType: [ + "cJSON_Delete", + this.nameForNamedType(unionType), + ], + items: undefined, + isNullable, + }; + }, ); } @@ -3569,7 +5558,10 @@ export class CJSONRenderer extends ConvenienceRenderer { */ protected startFile(proposedFilename: Sourcelike): void { /* Check if previous file is closed, create a new file */ - assert(this.currentFilename === undefined, "Previous file wasn't finished"); + assert( + this.currentFilename === undefined, + "Previous file wasn't finished", + ); if (proposedFilename !== undefined) { this.currentFilename = this.sourcelikeToString(proposedFilename); } @@ -3585,20 +5577,30 @@ 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(); /* Write include guard */ this.emitLine( "#ifndef __", - allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__" + 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"), "_")), - "__" + allUpperWordStyle( + this.currentFilename.replace( + new RegExp(/[^a-zA-Z0-9]+/, "g"), + "_", + ), + ), + "__", ); this.ensureBlankLine(); @@ -3647,8 +5649,13 @@ export class CJSONRenderer extends ConvenienceRenderer { /* Write include guard */ this.emitLine( "#endif /* __", - allUpperWordStyle(this.currentFilename.replace(new RegExp(/[^a-zA-Z0-9]+/, "g"), "_")), - "__ */" + allUpperWordStyle( + this.currentFilename.replace( + new RegExp(/[^a-zA-Z0-9]+/, "g"), + "_", + ), + ), + "__ */", ); this.ensureBlankLine(); @@ -3689,7 +5696,12 @@ export class CJSONRenderer extends ConvenienceRenderer { * @pram global: true if global include, false otherwise (default) */ protected emitIncludeLine(name: Sourcelike, global = false): void { - this.emitLine("#include ", global ? "<" : '"', name, global ? ">" : '"'); + this.emitLine( + "#include ", + global ? "<" : '"', + name, + global ? ">" : '"', + ); } /** @@ -3697,7 +5709,11 @@ export class CJSONRenderer extends ConvenienceRenderer { * @param lines: description block lines */ protected emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + this.emitCommentLines(lines, { + lineStart: " * ", + beforeComment: "/**", + afterComment: " */", + }); } /** @@ -3713,7 +5729,7 @@ export class CJSONRenderer extends ConvenienceRenderer { f: () => void, withName = "", withSemicolon = false, - withIndent = true + withIndent = true, ): void { this.emitLine(line, " {"); this.preventBlankLine(); @@ -3744,15 +5760,22 @@ 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) { this.updateIncludes(false, includes, type); } else if (type instanceof ClassType) { - this.forEachClassProperty(type, "none", (_name, _jsonName, property) => { - this.updateIncludes(true, includes, property.type); - }); + this.forEachClassProperty( + type, + "none", + (_name, _jsonName, property) => { + this.updateIncludes(true, includes, property.type); + }, + ); } /* Emit includes */ @@ -3774,16 +5797,26 @@ 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); - const propRecord: IncludeRecord = { kind: undefined, typeKind: undefined }; + const propRecord: IncludeRecord = { + kind: undefined, + typeKind: undefined, + }; if (t.type instanceof ClassType) { /* We can NOT forward declare direct class members, e.g. a class type is included at level#0 */ /* HOWEVER if it is not a direct class member, then we can SURELY forward declare it */ propRecord.typeKind = "class"; - propRecord.kind = t.level === 0 ? IncludeKind.Include : IncludeKind.ForwardDeclare; + propRecord.kind = + t.level === 0 + ? IncludeKind.Include + : IncludeKind.ForwardDeclare; if (t.forceInclude) { propRecord.kind = IncludeKind.Include; } @@ -3809,7 +5842,10 @@ 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 */ - if (incKind !== undefined && incKind.kind === IncludeKind.ForwardDeclare) { + if ( + incKind !== undefined && + incKind.kind === IncludeKind.ForwardDeclare + ) { includes.set(typeName, propRecord); } } else { @@ -3826,7 +5862,12 @@ export class CJSONRenderer extends ConvenienceRenderer { */ protected generatedTypes(isClassMember: boolean, type: 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, + ) => { if (t instanceof ArrayType) { recur(forceInclude, isVariant, l + 1, t.items); } else if (t instanceof ClassType) { @@ -3835,7 +5876,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); @@ -3845,7 +5886,7 @@ export class CJSONRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude: false + forceInclude: false, }); } else if (t instanceof UnionType) { /** @@ -3869,7 +5910,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/CJSON/constants.ts b/packages/quicktype-core/src/language/CJSON/constants.ts index cdccf419..6a0024c0 100644 --- a/packages/quicktype-core/src/language/CJSON/constants.ts +++ b/packages/quicktype-core/src/language/CJSON/constants.ts @@ -1,123 +1,122 @@ - /* 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" + /* 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/language.ts b/packages/quicktype-core/src/language/CJSON/language.ts index 7c3854c9..80563c04 100644 --- a/packages/quicktype-core/src/language/CJSON/language.ts +++ b/packages/quicktype-core/src/language/CJSON/language.ts @@ -21,10 +21,14 @@ * See test/languages.ts for the test cases which are not implmented/checked. */ -import { type RenderContext } from "../../Renderer"; -import { EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { CJSONRenderer } from "./CJSONRenderer"; @@ -35,7 +39,7 @@ const namingStyles = { "camel-case": "camel", "upper-underscore-case": "upper-underscore", "pascal-case-upper-acronyms": "pascal-upper-acronyms", - "camel-case-upper-acronyms": "camel-upper-acronyms" + "camel-case-upper-acronyms": "camel-upper-acronyms", } as const; /* cJSON generator options */ @@ -45,10 +49,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, } as const, "single-source", - "secondary" + "secondary", ), typeIntegerSize: new EnumOption( "integer-size", @@ -57,55 +61,67 @@ export const cJSONOptions = { int8_t: "int8_t", int16_t: "int16_t", int32_t: "int32_t", - int64_t: "int64_t" + int64_t: "int64_t", } as const, "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, } as const, "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, } as const, "print-formatted", - "secondary" + "secondary", + ), + typeNamingStyle: new EnumOption( + "type-style", + "Naming style for types", + namingStyles, + "pascal-case", + ), + memberNamingStyle: new EnumOption( + "member-style", + "Naming style for members", + namingStyles, + "underscore-case", ), - typeNamingStyle: new EnumOption("type-style", "Naming style for types", namingStyles, "pascal-case"), - memberNamingStyle: new EnumOption("member-style", "Naming style for members", namingStyles, "underscore-case"), enumeratorNamingStyle: new EnumOption( "enumerator-style", "Naming style for enumerators", namingStyles, - "upper-underscore-case" - ) + "upper-underscore-case", + ), }; /* cJSON generator target language */ export const cJSONLanguageConfig = { displayName: "C (cJSON)", names: ["cjson", "cJSON"], - extension: "h" + extension: "h", } as const; -export class CJSONTargetLanguage extends TargetLanguage { +export class CJSONTargetLanguage extends TargetLanguage< + typeof cJSONLanguageConfig +> { public constructor() { super(cJSONLanguageConfig); } @@ -140,7 +156,14 @@ export class CJSONTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index 2e74a50c..4a09e1c5 100644 --- a/packages/quicktype-core/src/language/CJSON/utils.ts +++ b/packages/quicktype-core/src/language/CJSON/utils.ts @@ -1,10 +1,16 @@ -import { type Name } from "../../Naming"; -import { type Sourcelike } from "../../Source"; -import { isAscii, isLetterOrUnderscoreOrDigit, legalizeCharacters } from "../../support/Strings"; -import { type Type, type TypeKind } from "../../Type"; +import type { Name } from "../../Naming"; +import type { Sourcelike } from "../../Source"; +import { + isAscii, + isLetterOrUnderscoreOrDigit, + legalizeCharacters, +} from "../../support/Strings"; +import type { Type, TypeKind } from "../../Type"; /* Function used to format names */ -export const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); +export const legalizeName = legalizeCharacters( + (cp) => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp), +); /* Used to build forbidden global names */ export enum GlobalNames { @@ -15,13 +21,13 @@ export enum GlobalNames { ValueTooShortException = 5, ValueTooLongException = 6, InvalidPatternException = 7, - CheckConstraint = 8 + 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" + Include = "Include", } /* Used to map includes */ diff --git a/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts b/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts index 1a232344..4013ebc7 100644 --- a/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/CPlusPlusRenderer.ts @@ -5,32 +5,62 @@ import { iterableSome, setUnion, toReadonlyArray, - withDefault + withDefault, } from "collection-utils"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +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 { + 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 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 { directlyReachableTypes, isNamedType, matchType, nullableFromUnion, - removeNullFromUnion + removeNullFromUnion, } from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type cPlusPlusOptions } from "./language"; +import type { cPlusPlusOptions } from "./language"; import { BaseString, type ConstraintMember, @@ -47,7 +77,7 @@ import { constraintsForType, legalizeName, optionalAsSharedType, - optionalFactoryAsSharedType + optionalFactoryAsSharedType, } from "./utils"; export class CPlusPlusRenderer extends ConvenienceRenderer { @@ -62,7 +92,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { private _allTypeNames: Set; - private readonly _gettersAndSettersForPropertyName = new Map(); + private readonly _gettersAndSettersForPropertyName = new Map< + Name, + [Name, Name, Name] + >(); private readonly _namespaceNames: readonly string[]; @@ -98,7 +131,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); @@ -106,11 +139,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._namespaceNames = _options.namespace.split("::"); this.typeNamingStyle = _options.typeNamingStyle; - this._namedTypeNameStyle = makeNameStyle(this.typeNamingStyle, legalizeName); + this._namedTypeNameStyle = makeNameStyle( + this.typeNamingStyle, + legalizeName, + ); this.enumeratorNamingStyle = _options.enumeratorNamingStyle; - this._memberNameStyle = makeNameStyle(_options.memberNamingStyle, legalizeName); - this._memberNamingFunction = funPrefixNamer("members", this._memberNameStyle); + this._memberNameStyle = makeNameStyle( + _options.memberNamingStyle, + legalizeName, + ); + this._memberNamingFunction = funPrefixNamer( + "members", + this._memberNameStyle, + ); this._gettersAndSettersForPropertyName = new Map(); this._allTypeNames = new Set(); @@ -241,15 +283,21 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { // Classes that don't require forward declarations can be stored // in std::optional ( or boost::optional ) private optionalType(t: Type): string { - if (this.isOptionalAsValuePossible(t)) return this.optionalTypeStack(); - else return this.optionalTypeHeap(); + if (this.isOptionalAsValuePossible(t)) { + return this.optionalTypeStack(); + } + + return this.optionalTypeHeap(); } // Returns a label that can be used to distinguish between // heap and stack based optional handling methods private optionalTypeLabel(t: Type): string { - if (this.isOptionalAsValuePossible(t)) return "stack"; - else return "heap"; + if (this.isOptionalAsValuePossible(t)) { + return "stack"; + } + + return "heap"; } protected getConstraintMembers(): ConstraintMember[] { @@ -258,45 +306,45 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { 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(), + }, ]; } @@ -315,7 +363,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } protected addMemberName(type: MemberNames): void { - this._generatedMemberNames.set(type, this._memberNameStyle(MemberNames[type])); + this._generatedMemberNames.set( + type, + this._memberNameStyle(MemberNames[type]), + ); } protected setupGlobalNames(): void { @@ -332,11 +383,17 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { 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 }; } @@ -353,7 +410,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enumerators", makeNameStyle(this.enumeratorNamingStyle, legalizeName)); + return funPrefixNamer( + "enumerators", + makeNameStyle(this.enumeratorNamingStyle, legalizeName), + ); } protected makeNamesForPropertyGetterAndSetter( @@ -361,15 +421,23 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { _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 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)}`, ); - const setterName = new DependencyName(this._memberNamingFunction, name.order, lookup => `set_${lookup(name)}`); return [getterName, mutableGetterName, setterName]; } @@ -378,9 +446,15 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { - const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); + const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter( + c, + className, + p, + jsonName, + name, + ); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return getterAndSetterNames; } @@ -388,17 +462,25 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { protected withConst(s: Sourcelike): Sourcelike { if (this._options.westConst) { return ["const ", s]; - } else { - return [s, " const"]; } + + return [s, " const"]; } protected emitInclude(global: boolean, name: Sourcelike): void { - this.emitLine("#include ", global ? "<" : '"', name, global ? ">" : '"'); + this.emitLine( + "#include ", + global ? "<" : '"', + name, + global ? ">" : '"', + ); } protected startFile(basename: Sourcelike, includeHelper = true): void { - assert(this._currentFilename === undefined, "Previous file wasn't finished"); + assert( + this._currentFilename === undefined, + "Previous file wasn't finished", + ); if (basename !== undefined) { this._currentFilename = this.sourcelikeToString(basename); } @@ -406,7 +488,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { if (this.leadingComments !== undefined) { this.emitComments(this.leadingComments); } else if (!this._options.justTypes) { - this.emitCommentLines([" To parse this JSON data, first install", ""]); + this.emitCommentLines([ + " To parse this JSON data, first install", + "", + ]); if (this._options.boost) { this.emitCommentLines([" Boost http://www.boost.org"]); } @@ -415,23 +500,38 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " json.hpp https://github.com/nlohmann/json", "", " Then include this file, and then do", - "" + "", ]); if (this._options.typeSourceStyle) { this.forEachTopLevel("none", (_, topLevelName) => { - this.emitLine("// ", topLevelName, " data = nlohmann::json::parse(jsonString);"); + this.emitLine( + "// ", + topLevelName, + " data = nlohmann::json::parse(jsonString);", + ); }); } else { - this.emitLine("// ", basename, " data = nlohmann::json::parse(jsonString);"); + 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"); + this.emitLine( + "// You can get std::wstring data back out using", + ); this.emitLine("//"); this.forEachTopLevel("none", (_, topLevelName) => { - this.emitLine("// std::wcout << ", "wdump((nlohmann::json) ", topLevelName, ");"); + this.emitLine( + "// std::wcout << ", + "wdump((nlohmann::json) ", + topLevelName, + ");", + ); }); } } @@ -487,10 +587,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } protected emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + 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) { @@ -507,7 +616,10 @@ 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) { @@ -517,7 +629,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ["namespace ", first], false, () => this.emitNamespaces(namesArray.slice(1), f), - namesArray.length === 1 + namesArray.length === 1, ); } } @@ -526,10 +638,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { 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); + return this.cppType( + defined(iterableFirst(nonNulls)), + ctx, + withIssues, + forceNarrowString, + false, + ); } const typeList: Sourcelike = []; @@ -544,12 +662,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: false, - inJsonNamespace: ctx.inJsonNamespace + inJsonNamespace: ctx.inJsonNamespace, }, withIssues, false, - false - ) + false, + ), ); } @@ -558,17 +676,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { 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."); + assert( + nonNulls.size >= 2, + "Variant not needed for less than two types.", + ); const indirection = maybeNull !== null; const variant = this.cppTypeInOptional( nonNulls, { needsForwardIndirection: !indirection, needsOptionalIndirection: !indirection, - inJsonNamespace + inJsonNamespace, }, true, - false + false, ); if (!indirection) { return variant; @@ -578,14 +699,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } protected ourQualifier(inJsonNamespace: boolean): Sourcelike { - return inJsonNamespace ? [arrayIntercalate("::", this._namespaceNames), "::"] : []; + return inJsonNamespace + ? [arrayIntercalate("::", this._namespaceNames), "::"] + : []; } 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, ">"]; } @@ -595,7 +722,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ctx: TypeContext, withIssues: boolean, forceNarrowString: boolean, - isOptional: boolean + isOptional: boolean, ): Sourcelike { const inJsonNamespace = ctx.inJsonNamespace; if (isOptional && t instanceof UnionType) { @@ -610,52 +737,57 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { const typeSource = matchType( t, - _anyType => { + (_anyType) => { isOptional = false; return maybeAnnotated(withIssues, anyTypeIssueAnnotation, [ this.jsonQualifier(inJsonNamespace), - "json" + "json", ]); }, - _nullType => { + (_nullType) => { isOptional = false; return maybeAnnotated(withIssues, nullTypeIssueAnnotation, [ this.jsonQualifier(inJsonNamespace), - "json" + "json", ]); }, - _boolType => "bool", - _integerType => "int64_t", - _doubleType => "double", - _stringType => { + (_boolType) => "bool", + (_integerType) => "int64_t", + (_doubleType) => "double", + (_stringType) => { if (forceNarrowString) { return "std::string"; - } else { - return this._stringType.getType(); } + + return this._stringType.getType(); }, - arrayType => [ + (arrayType) => [ "std::vector<", this.cppType( arrayType.items, { needsForwardIndirection: false, needsOptionalIndirection: true, - inJsonNamespace + inJsonNamespace, }, withIssues, forceNarrowString, - false + false, ), - ">" + ">", ], - classType => + (classType) => this.variantIndirection( classType, - ctx.needsForwardIndirection && this.isForwardDeclaredType(classType) && !isOptional, - [this.ourQualifier(inJsonNamespace), this.nameForNamedType(classType)] + ctx.needsForwardIndirection && + this.isForwardDeclaredType(classType) && + !isOptional, + [ + this.ourQualifier(inJsonNamespace), + this.nameForNamedType(classType), + ], ), - mapType => { + (mapType) => { let keyType = this._stringType.getType(); if (forceNarrowString) { keyType = "std::string"; @@ -670,17 +802,20 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: true, - inJsonNamespace + inJsonNamespace, }, withIssues, forceNarrowString, - false + false, ), - ">" + ">", ]; }, - enumType => [this.ourQualifier(inJsonNamespace), this.nameForNamedType(enumType)], - unionType => { + (enumType) => [ + this.ourQualifier(inJsonNamespace), + this.nameForNamedType(enumType), + ], + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { isOptional = true; @@ -689,16 +824,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace + inJsonNamespace, }, withIssues, forceNarrowString, - false + false, ); - } else { - return [this.ourQualifier(inJsonNamespace), this.nameForNamedType(unionType)]; } - } + + return [ + this.ourQualifier(inJsonNamespace), + this.nameForNamedType(unionType), + ]; + }, ); if (!isOptional) return typeSource; return [this.optionalType(t), "<", typeSource, ">"]; @@ -708,9 +846,17 @@ 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): void => { + 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) { @@ -719,7 +865,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); @@ -729,7 +875,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { type: t, level: l, variant: isVariant, - forceInclude: false + forceInclude: false, }); } else if (t instanceof UnionType) { /** @@ -753,7 +899,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 */ } @@ -779,7 +925,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { 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:"); @@ -790,17 +939,19 @@ 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 */ - const cnst = this.lookupGlobalName(GlobalNames.ClassMemberConstraints); + const cnst = this.lookupGlobalName( + GlobalNames.ClassMemberConstraints, + ); this.emitMember(cnst, this.constraintMember(jsonName)); } }); @@ -818,28 +969,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, ); /** @@ -847,12 +998,24 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { * One might as why the "this->xxx = value". Simple if we have * a member called 'value' value = value will screw up the compiler */ - const checkConst = this.lookupGlobalName(GlobalNames.CheckConstraint); + 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, "; }"); + this.emitLine( + rendered, + " ", + getterName, + "() const { return ", + name, + "; }", + ); if (constraints?.has(jsonName)) { this.emitLine( "void ", @@ -867,14 +1030,36 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.constraintMember(jsonName), ", *value); this->", name, - " = value; }" + " = value; }", ); } else { - this.emitLine("void ", setterName, "(", rendered, " value) { this->", name, " = value; }"); + this.emitLine( + "void ", + setterName, + "(", + rendered, + " value) { this->", + name, + " = value; }", + ); } } else { - this.emitLine(this.withConst(rendered), " & ", getterName, "() const { return ", name, "; }"); - this.emitLine(rendered, " & ", mutableGetterName, "() { return ", name, "; }"); + this.emitLine( + this.withConst(rendered), + " & ", + getterName, + "() const { return ", + name, + "; }", + ); + this.emitLine( + rendered, + " & ", + mutableGetterName, + "() { return ", + name, + "; }", + ); if (constraints?.has(jsonName)) { this.emitLine( "void ", @@ -889,7 +1074,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.constraintMember(jsonName), ", value); this->", name, - " = value; }" + " = value; }", ); } else { this.emitLine( @@ -899,7 +1084,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(rendered), " & value) { this->", name, - " = value; }" + " = value; }", ); } } @@ -909,7 +1094,9 @@ 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); @@ -922,23 +1109,31 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - property.isOptional + property.isOptional, ); res.set(jsonName, [ this.constraintMember(jsonName), "(", - minMax?.[0] && cppType === "int64_t" ? String(minMax[0]) : this._nulloptType, + minMax?.[0] && cppType === "int64_t" + ? String(minMax[0]) + : this._nulloptType, ", ", - minMax?.[1] && cppType === "int64_t" ? String(minMax[1]) : this._nulloptType, + minMax?.[1] && cppType === "int64_t" + ? String(minMax[1]) + : this._nulloptType, ", ", - minMax?.[0] && cppType === "double" ? String(minMax[0]) : this._nulloptType, + minMax?.[0] && cppType === "double" + ? String(minMax[0]) + : this._nulloptType, ", ", - minMax?.[1] && cppType === "double" ? String(minMax[1]) : this._nulloptType, + minMax?.[1] && cppType === "double" + ? String(minMax[1]) + : this._nulloptType, ", ", minMaxLength?.[0] ? String(minMaxLength[0]) : this._nulloptType, ", ", @@ -949,10 +1144,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { : [ this._stringType.getType(), "(", - this._stringType.createStringLiteral([stringEscape(pattern)]), - ")" + this._stringType.createStringLiteral([ + stringEscape(pattern), + ]), + ")", ], - ")" + ")", ]); }); @@ -961,34 +1158,40 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { 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); - if (this._options.codeFormat) { - this.emitLine("public:"); - if (constraints === undefined) { - this.emitLine(className, "() = default;"); - } else { - this.emitLine(className, "() :"); - let numEmits = 0; - constraints.forEach((initializer: Sourcelike, _propName: string) => { - numEmits++; - this.indent(() => { - if (numEmits === constraints.size) { - this.emitLine(initializer); - } else { - this.emitLine(initializer, ","); - } - }); - }); - this.emitLine("{}"); + this.emitBlock( + [this._options.codeFormat ? "class " : "struct ", className], + true, + () => { + const constraints = this.generateClassConstraints(c); + if (this._options.codeFormat) { + this.emitLine("public:"); + if (constraints === undefined) { + this.emitLine(className, "() = default;"); + } else { + this.emitLine(className, "() :"); + let numEmits = 0; + constraints.forEach( + (initializer: Sourcelike, _propName: string) => { + numEmits++; + this.indent(() => { + if (numEmits === constraints.size) { + this.emitLine(initializer); + } else { + this.emitLine(initializer, ","); + } + }); + }, + ); + this.emitLine("{}"); + } + + this.emitLine("virtual ~", className, "() = default;"); + this.ensureBlankLine(); } - this.emitLine("virtual ~", className, "() = default;"); - this.ensureBlankLine(); - } - - this.emitClassMembers(c, constraints); - }); + this.emitClassMembers(c, constraints); + }, + ); } protected emitTopLevelHeaders(t: Type, className: Name): void { @@ -996,26 +1199,45 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { if (t instanceof MapType && this._stringType !== this.NarrowString) { const ourQualifier = this.ourQualifier(true); - this.emitBlock(["struct adl_serializer<", ourQualifier, className, ">"], true, () => { - this.emitLine("template <>"); - this.emitLine( - "static void from_json(", - this.withConst("json"), - " & j, ", - ourQualifier, - className, - " & x);" - ); - this.emitLine("static void to_json(json & j, ", this.withConst([ourQualifier, className]), " & x);"); - }); + this.emitBlock( + ["struct adl_serializer<", ourQualifier, className, ">"], + true, + () => { + this.emitLine("template <>"); + this.emitLine( + "static void from_json(", + this.withConst("json"), + " & j, ", + ourQualifier, + className, + " & x);", + ); + this.emitLine( + "static void to_json(json & j, ", + this.withConst([ourQualifier, className]), + " & x);", + ); + }, + ); } } 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);"); + 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 { @@ -1035,7 +1257,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " & j, ", ourQualifier, className, - "& x)" + "& x)", ], false, () => { @@ -1044,34 +1266,35 @@ 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([ "x = ", - this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ - "j.get<", + this._stringType.wrapEncodingChange( + [ourQualifier], cppType, - ">()" - ]), - ";" + toType, + ["j.get<", cppType, ">()"], + ), + ";", ]); - } + }, ); this.emitBlock( @@ -1081,7 +1304,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { className, ">::to_json(json & j, ", this.withConst([ourQualifier, className]), - " & x)" + " & x)", ], false, () => { @@ -1090,30 +1313,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"), - ";" + this._stringType.wrapEncodingChange( + [ourQualifier], + cppType, + toType, + "x", + ), + ";", ]); - } + }, ); } } @@ -1124,16 +1352,28 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { let toType: Sourcelike; this.emitBlock( - ["inline void from_json(", this.withConst("json"), " & j, ", ourQualifier, className, "& x)"], + [ + "inline void from_json(", + this.withConst("json"), + " & j, ", + ourQualifier, + className, + "& x)", + ], false, () => { this.forEachClassProperty(c, "none", (name, json, p) => { - const [, , setterName] = defined(this._gettersAndSettersForPropertyName.get(name)); + const [, , setterName] = defined( + this._gettersAndSettersForPropertyName.get(name), + ); const propType = p.type; let assignment: WrappingCode; if (this._options.codeFormat) { - assignment = new WrappingCode(["x.", setterName, "("], [")"]); + assignment = new WrappingCode( + ["x.", setterName, "("], + [")"], + ); } else { assignment = new WrappingCode(["x.", name, " = "], []); } @@ -1149,26 +1389,37 @@ 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] { + const [nullOrOptional, typeSet] = ((): [ + boolean, + ReadonlySet, + ] => { if (propType instanceof UnionType) { - const [maybeNull, nonNulls] = removeNullFromUnion(propType, true); - return [maybeNull !== null || p.isOptional, nonNulls]; - } else { - const set = new Set(); - set.add(propType); - return [true, set]; + const [maybeNull, nonNulls] = + removeNullFromUnion(propType, true); + return [ + maybeNull !== null || p.isOptional, + nonNulls, + ]; } + + const set = new Set(); + set.add(propType); + return [true, set]; })(); if (nullOrOptional) { cppType = this.cppTypeInOptional( @@ -1176,20 +1427,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( @@ -1197,8 +1448,18 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ this._stringType.wrapEncodingChange( [ourQualifier], - [this.optionalType(propType), "<", cppType, ">"], - [this.optionalType(propType), "<", toType, ">"], + [ + this.optionalType(propType), + "<", + cppType, + ">", + ], + [ + this.optionalType(propType), + "<", + toType, + ">", + ], [ ourQualifier, `get_${this.optionalTypeLabel(propType)}_optional<`, @@ -1208,14 +1469,22 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { [ourQualifier], this._stringType.getType(), this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(json)])] + [ + this._stringType.createStringLiteral( + [ + stringEscape( + json, + ), + ], + ), + ], ), - ")" - ] - ) - ] + ")", + ], + ), + ], ), - ";" + ";", ); return; } @@ -1226,48 +1495,59 @@ 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( [], - this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ - "j.at(", - this._stringType.wrapEncodingChange( - [ourQualifier], - this._stringType.getType(), - this.NarrowString.getType(), - this._stringType.createStringLiteral([stringEscape(json)]) - ), - ").get<", + this._stringType.wrapEncodingChange( + [ourQualifier], cppType, - ">()" - ]) + toType, + [ + "j.at(", + this._stringType.wrapEncodingChange( + [ourQualifier], + this._stringType.getType(), + this.NarrowString.getType(), + this._stringType.createStringLiteral([ + stringEscape(json), + ]), + ), + ").get<", + cppType, + ">()", + ], + ), ), - ";" + ";", ); }); - } + }, ); this.ensureBlankLine(); this.emitBlock( - ["inline void to_json(json & j, ", this.withConst([ourQualifier, className]), " & x)"], + [ + "inline void to_json(json & j, ", + this.withConst([ourQualifier, className]), + " & x)", + ], false, () => { this.emitLine("j = json::object();"); @@ -1278,24 +1558,26 @@ 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), ); - const [getterName, ,] = defined(this._gettersAndSettersForPropertyName.get(name)); let getter: Sourcelike[]; if (this._options.codeFormat) { getter = [getterName, "()"]; @@ -1309,29 +1591,41 @@ 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]), - ";" + 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]), - ")" + this._stringType.wrapEncodingChange( + [ourQualifier], + cppType, + toType, + ["x.", getter], + ), + ")", ], false, () => { this.emitLine(assignment); - } + }, ); } else { this.emitLine(assignment); } }); - } + }, ); } @@ -1351,11 +1645,25 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } }); this.emitDescription(this.descriptionForType(e)); - this.emitLine("enum class ", enumName, " : ", this._enumType, " { ", caseNames, " };"); + this.emitLine( + "enum class ", + enumName, + " : ", + this._enumType, + " { ", + caseNames, + " };", + ); } protected emitUnionTypedefs(u: UnionType, unionName: Name): void { - this.emitLine("using ", unionName, " = ", this.variantType(u, false), ";"); + this.emitLine( + "using ", + unionName, + " = ", + this.variantType(u, false), + ";", + ); } protected emitUnionHeaders(u: UnionType): void { @@ -1371,17 +1679,31 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false + false, ); this.emitLine("template <>"); - this.emitBlock(["struct adl_serializer<", variantType, ">"], true, () => { - this.emitLine("static void from_json(", this.withConst("json"), " & j, ", variantType, " & x);"); - this.emitLine("static void to_json(json & j, ", this.withConst(variantType), " & x);"); - }); + this.emitBlock( + ["struct adl_serializer<", variantType, ">"], + true, + () => { + this.emitLine( + "static void from_json(", + this.withConst("json"), + " & j, ", + variantType, + " & x);", + ); + this.emitLine( + "static void to_json(json & j, ", + this.withConst(variantType), + " & x);", + ); + }, + ); } protected emitUnionFunctions(u: UnionType): void { @@ -1397,7 +1719,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( @@ -1405,10 +1727,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false + false, ); this.emitBlock( @@ -1419,112 +1741,153 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst("json"), " & j, ", variantType, - " & x)" + " & x)", ], false, () => { let onFirst = true; for (const [kind, func] of functionForKind) { - const typeForKind = iterableFind(nonNulls, t => t.kind === kind); + const typeForKind = iterableFind( + nonNulls, + (t) => t.kind === kind, + ); if (typeForKind === undefined) continue; - this.emitLine(onFirst ? "if" : "else if", " (j.", func, "())"); + this.emitLine( + onFirst ? "if" : "else if", + " (j.", + func, + "())", + ); this.indent(() => { const cppType = this.cppType( typeForKind, { 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<", + 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(); this.emitBlock( - ["inline void adl_serializer<", variantType, ">::to_json(json & j, ", this.withConst(variantType), " & x)"], + [ + "inline void adl_serializer<", + variantType, + ">::to_json(json & j, ", + this.withConst(variantType), + " & x)", + ], false, () => { - this.emitBlock(["switch (x.", this._variantIndexMethodName, "())"], false, () => { - let i = 0; - for (const t of nonNulls) { - this.emitLine("case ", i.toString(), ":"); - this.indent(() => { - const cppType = this.cppType( - t, - { - needsForwardIndirection: true, - needsOptionalIndirection: true, - inJsonNamespace: true - }, - false, - false, - false - ); - const toType = this.cppType( - t, - { - needsForwardIndirection: true, - needsOptionalIndirection: true, - inJsonNamespace: true - }, - false, - true, - false - ); - this.emitLine( - "j = ", - this._stringType.wrapEncodingChange([ourQualifier], cppType, toType, [ - this._options.boost ? "boost::get<" : "std::get<", - cppType, - ">(x)" - ]), - ";" - ); - this.emitLine("break;"); - }); - i++; - } + this.emitBlock( + ["switch (x.", this._variantIndexMethodName, "())"], + false, + () => { + let i = 0; + for (const t of nonNulls) { + this.emitLine("case ", i.toString(), ":"); + this.indent(() => { + const cppType = this.cppType( + t, + { + needsForwardIndirection: true, + needsOptionalIndirection: true, + inJsonNamespace: true, + }, + false, + false, + false, + ); + const toType = this.cppType( + t, + { + needsForwardIndirection: true, + needsOptionalIndirection: true, + inJsonNamespace: true, + }, + false, + true, + false, + ); + this.emitLine( + "j = ", + this._stringType.wrapEncodingChange( + [ourQualifier], + cppType, + toType, + [ + this._options.boost + ? "boost::get<" + : "std::get<", + cppType, + ">(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 { 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);"); + 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): boolean { @@ -1537,7 +1900,14 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { const ourQualifier = this.ourQualifier(false); this.emitBlock( - ["inline void from_json(", this.withConst("json"), " & j, ", ourQualifier, enumName, " & x)"], + [ + "inline void from_json(", + this.withConst("json"), + " & j, ", + ourQualifier, + enumName, + " & x)", + ], false, () => { if (this.isLargeEnum(e)) { @@ -1548,34 +1918,48 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { ", ", ourQualifier, enumName, - "> enumValues" + "> enumValues", ], true, () => { - this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine( - "{", - this._stringType.wrapEncodingChange( - [ourQualifier], - this._stringType.getType(), - this.NarrowString.getType(), - [this._stringType.createStringLiteral([stringEscape(jsonName)])] - ), - ", ", - ourQualifier, - enumName, - "::", - name, - "}," - ); - }); - } + this.forEachEnumCase( + e, + "none", + (name, jsonName) => { + this.emitLine( + "{", + this._stringType.wrapEncodingChange( + [ourQualifier], + this._stringType.getType(), + this.NarrowString.getType(), + [ + this._stringType.createStringLiteral( + [stringEscape(jsonName)], + ), + ], + ), + ", ", + ourQualifier, + enumName, + "::", + name, + "},", + ); + }, + ); + }, ); - this.emitLine(`auto iter = enumValues.find(j.get<${this._stringType.getType()}>());`); - this.emitBlock("if (iter != enumValues.end())", false, () => { - this.emitLine("x = iter->second;"); - }); + this.emitLine( + `auto iter = enumValues.find(j.get<${this._stringType.getType()}>());`, + ); + this.emitBlock( + "if (iter != enumValues.end())", + false, + () => { + this.emitLine("x = iter->second;"); + }, + ); } else { let onFirst = true; this.forEachEnumCase(e, "none", (name, jsonName) => { @@ -1587,25 +1971,35 @@ 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(); this.emitBlock( - ["inline void to_json(json & j, ", this.withConst([ourQualifier, enumName]), " & x)"], + [ + "inline void to_json(json & j, ", + this.withConst([ourQualifier, enumName]), + " & x)", + ], false, () => { this.emitBlock("switch (x)", false, () => { @@ -1621,18 +2015,22 @@ 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)));` + `\\": " + std::to_string(static_cast(x)));`, ); }); - } + }, ); } @@ -1646,53 +2044,53 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: false + inJsonNamespace: false, }, true, false, - false + false, ), - ";" + ";", ); } protected emitAllUnionFunctions(): void { this.forEachUniqueUnion( "leading-and-interposing", - u => + (u) => this.sourcelikeToString( this.cppTypeInOptional( removeNullFromUnion(u, true)[1], { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false - ) + false, + ), ), - (u: UnionType) => this.emitUnionFunctions(u) + (u: UnionType) => this.emitUnionFunctions(u), ); } protected emitAllUnionHeaders(): void { this.forEachUniqueUnion( "interposing", - u => + (u) => this.sourcelikeToString( this.cppTypeInOptional( removeNullFromUnion(u, true)[1], { needsForwardIndirection: false, needsOptionalIndirection: false, - inJsonNamespace: true + inJsonNamespace: true, }, false, - false - ) + false, + ), ), - (u: UnionType) => this.emitUnionHeaders(u) + (u: UnionType) => this.emitUnionHeaders(u), ); } @@ -1703,31 +2101,50 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitNamespaces(["nlohmann"], () => { const emitAdlStruct = (optType: string, factory: string): void => { this.emitLine("template "); - this.emitBlock(["struct adl_serializer<", optType, ">"], true, () => { - this.emitBlock( - ["static void to_json(json & j, ", this.withConst([optType, ""]), " & opt)"], - false, - () => { - this.emitLine("if (!opt) j = nullptr; else j = *opt;"); - } - ); + this.emitBlock( + ["struct adl_serializer<", optType, ">"], + true, + () => { + this.emitBlock( + [ + "static void to_json(json & j, ", + this.withConst([optType, ""]), + " & opt)", + ], + false, + () => { + this.emitLine( + "if (!opt) j = nullptr; else j = *opt;", + ); + }, + ); - this.ensureBlankLine(); + this.ensureBlankLine(); - this.emitBlock( - ["static ", optType, " from_json(", this.withConst("json"), " & j)"], - false, - () => { - this.emitLine( - `if (j.is_null()) return ${factory}(); else return ${factory}(j.get());` - ); - } - ); - }); + this.emitBlock( + [ + "static ", + optType, + " from_json(", + this.withConst("json"), + " & j)", + ], + false, + () => { + this.emitLine( + `if (j.is_null()) return ${factory}(); else return ${factory}(j.get());`, + ); + }, + ); + }, + ); }; emitAdlStruct(this.optionalTypeHeap(), this.optionalFactoryHeap()); - emitAdlStruct(this.optionalTypeStack(), this.optionalFactoryStack()); + emitAdlStruct( + this.optionalTypeStack(), + this.optionalFactoryStack(), + ); }); this.emitLine("#endif"); @@ -1757,9 +2174,32 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } } - 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 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( @@ -1767,7 +2207,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { classConstraint: string, getterMinValue: string, getterMaxValue: string, - cppType: string + cppType: string, ): void { this.emitBlock( [ @@ -1779,19 +2219,31 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(classConstraint), " & c, ", cppType, - " value)" + " value)", ], false, () => { this.emitBlock( - ["if (c.", getterMinValue, "() != ", this._nulloptType, " && value < *c.", getterMinValue, "())"], + [ + "if (c.", + getterMinValue, + "() != ", + this._nulloptType, + " && value < *c.", + getterMinValue, + "())", + ], false, () => { this.emitLine( "throw ", - this.lookupGlobalName(GlobalNames.ValueTooLowException), + this.lookupGlobalName( + GlobalNames.ValueTooLowException, + ), " (", - this._stringType.createStringLiteral(["Value too low for "]), + this._stringType.createStringLiteral([ + "Value too low for ", + ]), " + name + ", this._stringType.createStringLiteral([" ("]), " + ", @@ -1799,24 +2251,40 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " + ", this._stringType.createStringLiteral(["<"]), " + ", - this._stringType.wrapToString(["*c.", getterMinValue, "()"]), + this._stringType.wrapToString([ + "*c.", + getterMinValue, + "()", + ]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); this.emitBlock( - ["if (c.", getterMaxValue, "() != ", this._nulloptType, " && value > *c.", getterMaxValue, "())"], + [ + "if (c.", + getterMaxValue, + "() != ", + this._nulloptType, + " && value > *c.", + getterMaxValue, + "())", + ], false, () => { this.emitLine( "throw ", - this.lookupGlobalName(GlobalNames.ValueTooHighException), + this.lookupGlobalName( + GlobalNames.ValueTooHighException, + ), " (", - this._stringType.createStringLiteral(["Value too high for "]), + this._stringType.createStringLiteral([ + "Value too high for ", + ]), " + name + ", this._stringType.createStringLiteral([" ("]), " + ", @@ -1824,15 +2292,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " + ", this._stringType.createStringLiteral([">"]), " + ", - this._stringType.wrapToString(["*c.", getterMaxValue, "()"]), + this._stringType.wrapToString([ + "*c.", + getterMaxValue, + "()", + ]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); - } + }, ); this.ensureBlankLine(); } @@ -1840,30 +2312,55 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { protected emitConstraintClasses(): void { const ourQualifier = this.ourQualifier(false) as string; - const getterMinIntValue = this.lookupMemberName(MemberNames.GetMinIntValue); - const getterMaxIntValue = this.lookupMemberName(MemberNames.GetMaxIntValue); - const getterMinDoubleValue = this.lookupMemberName(MemberNames.GetMinDoubleValue); - const getterMaxDoubleValue = this.lookupMemberName(MemberNames.GetMaxDoubleValue); + const getterMinIntValue = this.lookupMemberName( + MemberNames.GetMinIntValue, + ); + const getterMaxIntValue = this.lookupMemberName( + MemberNames.GetMaxIntValue, + ); + const getterMinDoubleValue = this.lookupMemberName( + MemberNames.GetMinDoubleValue, + ); + const getterMaxDoubleValue = this.lookupMemberName( + MemberNames.GetMaxDoubleValue, + ); const getterMinLength = this.lookupMemberName(MemberNames.GetMinLength); const getterMaxLength = this.lookupMemberName(MemberNames.GetMaxLength); const getterPattern = this.lookupMemberName(MemberNames.GetPattern); - const classConstraint = this.lookupGlobalName(GlobalNames.ClassMemberConstraints); + const classConstraint = this.lookupGlobalName( + GlobalNames.ClassMemberConstraints, + ); this.emitBlock(["class ", classConstraint], true, () => { this.emitLine("private:"); - const constraintMembers: ConstraintMember[] = this.getConstraintMembers(); + const constraintMembers: ConstraintMember[] = + this.getConstraintMembers(); for (const member of constraintMembers) { - this.emitMember([this._optionalType, "<", member.cppType, ">"], this.lookupMemberName(member.name)); + this.emitMember( + [this._optionalType, "<", member.cppType, ">"], + this.lookupMemberName(member.name), + ); } this.ensureBlankLine(); this.emitLine("public:"); this.emitLine(classConstraint, "("); this.indent(() => { - this.iterableForEach(constraintMembers, ({ name, cppType }, pos) => { - const comma = pos === "first" || pos === "middle" ? "," : []; - this.emitLine(this._optionalType, "<", cppType, "> ", this.lookupMemberName(name), comma); - }); + this.iterableForEach( + constraintMembers, + ({ name, cppType }, pos) => { + const comma = + pos === "first" || pos === "middle" ? "," : []; + this.emitLine( + this._optionalType, + "<", + cppType, + "> ", + this.lookupMemberName(name), + comma, + ); + }, + ); }); const args = constraintMembers.map(({ name }) => { @@ -1880,29 +2377,35 @@ 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), ); } }); this.ensureBlankLine(); - const classConstEx = this.lookupGlobalName(GlobalNames.ClassMemberConstraintException); - this.emitBlock(["class ", classConstEx, " : public std::runtime_error"], true, () => { - this.emitLine("public:"); - this.emitLine( - classConstEx, - "(", - this._stringType.getConstType(), - " msg) : std::runtime_error(", - this._stringType.wrapEncodingChange( - [ourQualifier], - this._stringType.getType(), - this.NarrowString.getType(), - ["msg"] - ), - ") {}" - ); - }); + const classConstEx = this.lookupGlobalName( + GlobalNames.ClassMemberConstraintException, + ); + this.emitBlock( + ["class ", classConstEx, " : public std::runtime_error"], + true, + () => { + this.emitLine("public:"); + this.emitLine( + classConstEx, + "(", + this._stringType.getConstType(), + " msg) : std::runtime_error(", + this._stringType.wrapEncodingChange( + [ourQualifier], + this._stringType.getType(), + this.NarrowString.getType(), + ["msg"], + ), + ") {}", + ); + }, + ); this.ensureBlankLine(); const exceptions: GlobalNames[] = [ @@ -1910,26 +2413,43 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { GlobalNames.ValueTooHighException, GlobalNames.ValueTooShortException, GlobalNames.ValueTooLongException, - GlobalNames.InvalidPatternException + GlobalNames.InvalidPatternException, ]; for (const ex of exceptions) { const name = this.lookupGlobalName(ex); - this.emitBlock(["class ", name, " : public ", classConstEx], true, () => { - this.emitLine("public:"); - this.emitLine(name, "(", this._stringType.getConstType(), " msg) : ", classConstEx, "(msg) {}"); - }); + this.emitBlock( + ["class ", name, " : public ", classConstEx], + true, + () => { + this.emitLine("public:"); + this.emitLine( + name, + "(", + this._stringType.getConstType(), + " msg) : ", + classConstEx, + "(msg) {}", + ); + }, + ); this.ensureBlankLine(); } const checkConst = this.lookupGlobalName(GlobalNames.CheckConstraint); - this.emitNumericCheckConstraints(checkConst, classConstraint, getterMinIntValue, getterMaxIntValue, "int64_t"); + this.emitNumericCheckConstraints( + checkConst, + classConstraint, + getterMinIntValue, + getterMaxIntValue, + "int64_t", + ); this.emitNumericCheckConstraints( checkConst, classConstraint, getterMinDoubleValue, getterMaxDoubleValue, - "double" + "double", ); this.emitBlock( @@ -1942,7 +2462,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst(classConstraint), " & c, ", this._stringType.getConstType(), - " value)" + " value)", ], false, () => { @@ -1954,15 +2474,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._nulloptType, " && value.length() < *c.", getterMinLength, - "())" + "())", ], false, () => { this.emitLine( "throw ", - this.lookupGlobalName(GlobalNames.ValueTooShortException), + this.lookupGlobalName( + GlobalNames.ValueTooShortException, + ), " (", - this._stringType.createStringLiteral(["Value too short for "]), + this._stringType.createStringLiteral([ + "Value too short for ", + ]), " + name + ", this._stringType.createStringLiteral([" ("]), " + ", @@ -1970,12 +2494,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " + ", this._stringType.createStringLiteral(["<"]), " + ", - this._stringType.wrapToString(["*c.", getterMinLength, "()"]), + this._stringType.wrapToString([ + "*c.", + getterMinLength, + "()", + ]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); @@ -1987,15 +2515,19 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._nulloptType, " && value.length() > *c.", getterMaxLength, - "())" + "())", ], false, () => { this.emitLine( "throw ", - this.lookupGlobalName(GlobalNames.ValueTooLongException), + this.lookupGlobalName( + GlobalNames.ValueTooLongException, + ), " (", - this._stringType.createStringLiteral(["Value too long for "]), + this._stringType.createStringLiteral([ + "Value too long for ", + ]), " + name + ", this._stringType.createStringLiteral([" ("]), " + ", @@ -2003,44 +2535,56 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { " + ", this._stringType.createStringLiteral([">"]), " + ", - this._stringType.wrapToString(["*c.", getterMaxLength, "()"]), + this._stringType.wrapToString([ + "*c.", + getterMaxLength, + "()", + ]), " + ", this._stringType.createStringLiteral([")"]), - ");" + ");", ); - } + }, ); this.ensureBlankLine(); - this.emitBlock(["if (c.", getterPattern, "() != ", this._nulloptType, ")"], false, () => { - this.emitLine(this._stringType.getSMatch(), " result;"); - this.emitLine( - "std::regex_search(value, result, ", - this._stringType.getRegex(), - "( *c.", - getterPattern, - "() ));" - ); - this.emitBlock(["if (result.empty())"], false, () => { + this.emitBlock( + ["if (c.", getterPattern, "() != ", this._nulloptType, ")"], + false, + () => { + this.emitLine(this._stringType.getSMatch(), " result;"); this.emitLine( - "throw ", - this.lookupGlobalName(GlobalNames.InvalidPatternException), - " (", - this._stringType.createStringLiteral(["Value doesn't match pattern for "]), - " + name + ", - this._stringType.createStringLiteral([" ("]), - " + value +", - this._stringType.createStringLiteral([" != "]), - " + *c.", + "std::regex_search(value, result, ", + this._stringType.getRegex(), + "( *c.", getterPattern, - "() + ", - this._stringType.createStringLiteral([")"]), - ");" + "() ));", ); - }); - }); + this.emitBlock(["if (result.empty())"], false, () => { + this.emitLine( + "throw ", + this.lookupGlobalName( + GlobalNames.InvalidPatternException, + ), + " (", + this._stringType.createStringLiteral([ + "Value doesn't match pattern for ", + ]), + " + name + ", + this._stringType.createStringLiteral([" ("]), + " + value +", + this._stringType.createStringLiteral([" != "]), + " + *c.", + getterPattern, + "() + ", + this._stringType.createStringLiteral([")"]), + ");", + ); + }); + }, + ); this.ensureBlankLine(); - } + }, ); } @@ -2049,7 +2593,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { if ( this._options.codeFormat && - iterableSome(this.typeGraph.allTypesUnordered(), t => constraintsForType(t) !== undefined) + iterableSome( + this.typeGraph.allTypesUnordered(), + (t) => constraintsForType(t) !== undefined, + ) ) { this.emitConstraintClasses(); this.ensureBlankLine(); @@ -2059,7 +2606,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { let untypedMacroName = "NLOHMANN_UNTYPED_"; let optionalMacroName = "NLOHMANN_OPTIONAL_"; - this._namespaceNames.forEach(value => { + this._namespaceNames.forEach((value) => { // We can't use upper name, because namespaces are case sensitive untypedMacroName += value; untypedMacroName += "_"; @@ -2075,24 +2622,38 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine(`#define ${untypedMacroName}`); this.emitBlock( - ["inline json get_untyped(", this.withConst("json"), " & j, ", this.withConst("char"), " * property)"], + [ + "inline json get_untyped(", + this.withConst("json"), + " & j, ", + this.withConst("char"), + " * property)", + ], false, () => { - this.emitBlock(["if (j.find(property) != j.end())"], false, () => { - this.emitLine("return j.at(property).get();"); - }); + this.emitBlock( + ["if (j.find(property) != j.end())"], + false, + () => { + this.emitLine("return j.at(property).get();"); + }, + ); this.emitLine("return json();"); - } + }, ); this.ensureBlankLine(); this.emitBlock( - ["inline json get_untyped(", this.withConst("json"), " & j, std::string property)"], + [ + "inline json get_untyped(", + this.withConst("json"), + " & j, std::string property)", + ], false, () => { this.emitLine("return get_untyped(j, property.data());"); - } + }, ); this.emitLine("#endif"); @@ -2105,7 +2666,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitLine(`#ifndef ${optionalMacroName}`); this.emitLine(`#define ${optionalMacroName}`); - const emitGetOptional = (optionalType: string, label: string): void => { + const emitGetOptional = ( + optionalType: string, + label: string, + ): void => { this.emitLine("template "); this.emitBlock( [ @@ -2115,16 +2679,24 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.withConst("json"), " & j, ", this.withConst("char"), - " * property)" + " * property)", ], false, () => { this.emitLine(["auto it = j.find(property);"]); - this.emitBlock(["if (it != j.end() && !it->is_null())"], false, () => { - this.emitLine("return j.at(property).get<", optionalType, ">();"); - }); + this.emitBlock( + ["if (it != j.end() && !it->is_null())"], + false, + () => { + this.emitLine( + "return j.at(property).get<", + optionalType, + ">();", + ); + }, + ); this.emitLine("return ", optionalType, "();"); - } + }, ); this.ensureBlankLine(); @@ -2136,12 +2708,14 @@ 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());`); - } + this.emitLine( + `return get_${label}_optional(j, property.data());`, + ); + }, ); }; @@ -2174,7 +2748,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } // Include unordered_map if contains large enums - if (Array.from(this.enums).some(enumType => this.isLargeEnum(enumType))) { + if ( + Array.from(this.enums).some((enumType) => + this.isLargeEnum(enumType), + ) + ) { this.emitInclude(true, "unordered_map"); } @@ -2209,29 +2787,38 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitHelperFunctions(); } - this.forEachDeclaration("interposing", decl => this.emitDeclaration(decl)); + 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[] { return this.gatherSource(() => { - this.forEachObject("leading-and-interposing", (_: unknown, className: Name) => - this.emitClassHeaders(className) + this.forEachObject( + "leading-and-interposing", + (_: unknown, className: Name) => + this.emitClassHeaders(className), ); - this.forEachEnum("leading-and-interposing", (_: unknown, enumName: Name) => this.emitEnumHeaders(enumName)); + this.forEachEnum( + "leading-and-interposing", + (_: unknown, enumName: Name) => this.emitEnumHeaders(enumName), + ); }); } protected gatherNlohmannNamespaceForwardDecls(): Sourcelike[] { return this.gatherSource(() => { - this.forEachTopLevel("leading-and-interposing", (t: Type, className: Name) => - this.emitTopLevelHeaders(t, className) + this.forEachTopLevel( + "leading-and-interposing", + (t: Type, className: Name) => + this.emitTopLevelHeaders(t, className), ); this.ensureBlankLine(); @@ -2241,12 +2828,16 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { } protected emitUserNamespaceImpls(): void { - this.forEachObject("leading-and-interposing", (c: ClassType, className: Name) => - this.emitClassFunctions(c, className) + this.forEachObject( + "leading-and-interposing", + (c: ClassType, className: Name) => + this.emitClassFunctions(c, className), ); - this.forEachEnum("leading-and-interposing", (e: EnumType, enumName: Name) => - this.emitEnumFunctions(e, enumName) + this.forEachEnum( + "leading-and-interposing", + (e: EnumType, enumName: Name) => + this.emitEnumFunctions(e, enumName), ); } @@ -2254,7 +2845,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { 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(); @@ -2269,30 +2860,42 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.emitNamespaces(this._namespaceNames, () => { didEmit = this.forEachTopLevel( "none", - (t: Type, name: Name) => this.emitTopLevelTypedef(t, name), - t => this.namedTypeToNameForTopLevel(t) === undefined + (t: Type, name: Name) => + this.emitTopLevelTypedef(t, name), + (t) => this.namedTypeToNameForTopLevel(t) === undefined, ); - }) + }), ); if (didEmit) { this.emitGatheredSource(gathered); this.ensureBlankLine(); } } else { - const userNamespaceForwardDecls = this.gatherUserNamespaceForwardDecls(); - const nlohmannNamespaceForwardDecls = this.gatherNlohmannNamespaceForwardDecls(); + const userNamespaceForwardDecls = + this.gatherUserNamespaceForwardDecls(); + const nlohmannNamespaceForwardDecls = + this.gatherNlohmannNamespaceForwardDecls(); - if (userNamespaceForwardDecls.length === 0 && nlohmannNamespaceForwardDecls.length > 0) { + if ( + userNamespaceForwardDecls.length === 0 && + nlohmannNamespaceForwardDecls.length > 0 + ) { this.emitNamespaces(["nlohmann"], () => { this.emitGatheredSource(nlohmannNamespaceForwardDecls); this.emitNlohmannNamespaceImpls(); }); - } else if (userNamespaceForwardDecls.length > 0 && nlohmannNamespaceForwardDecls.length === 0) { + } else if ( + userNamespaceForwardDecls.length > 0 && + nlohmannNamespaceForwardDecls.length === 0 + ) { this.emitNamespaces(this._namespaceNames, () => { this.emitGatheredSource(userNamespaceForwardDecls); this.emitUserNamespaceImpls(); }); - } else if (userNamespaceForwardDecls.length > 0 && nlohmannNamespaceForwardDecls.length > 0) { + } else if ( + userNamespaceForwardDecls.length > 0 && + nlohmannNamespaceForwardDecls.length > 0 + ) { this.emitNamespaces(this._namespaceNames, () => { this.emitGatheredSource(userNamespaceForwardDecls); }); @@ -2318,7 +2921,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { if (this._options.justTypes) { this.emitTypes(); } else { - if (!this._options.justTypes && this.haveNamedTypes && (this.haveUnions || this.haveOptionalProperties)) { + if ( + !this._options.justTypes && + this.haveNamedTypes && + (this.haveUnions || this.haveOptionalProperties) + ) { this.emitOptionalHelpers(); this.ensureBlankLine(); } @@ -2333,13 +2940,21 @@ 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) { const typeName = this.sourcelikeToString(t.name); - const propRecord: IncludeRecord = { kind: undefined, typeKind: undefined }; + const propRecord: IncludeRecord = { + kind: undefined, + typeKind: undefined, + }; if (t.type instanceof ClassType) { /** @@ -2348,7 +2963,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { * - level > 0 - then we can SURELY forward declare it. */ propRecord.typeKind = "class"; - propRecord.kind = t.level === 0 ? IncludeKind.Include : IncludeKind.ForwardDeclare; + propRecord.kind = + t.level === 0 + ? IncludeKind.Include + : IncludeKind.ForwardDeclare; if (t.forceInclude) { propRecord.kind = IncludeKind.Include; } @@ -2377,7 +2995,10 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { * If we already include the type as typed include, * do not write it over with forward declare */ - if (incKind !== undefined && incKind.kind === IncludeKind.ForwardDeclare) { + if ( + incKind !== undefined && + incKind.kind === IncludeKind.ForwardDeclare + ) { includes.set(typeName, propRecord); } } else { @@ -2386,7 +3007,10 @@ 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 @@ -2396,9 +3020,13 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { if (c instanceof UnionType) { this.updateIncludes(false, includes, c, defName); } else if (c instanceof ClassType) { - this.forEachClassProperty(c, "none", (_name, _jsonName, property) => { - this.updateIncludes(true, includes, property.type, defName); - }); + this.forEachClassProperty( + c, + "none", + (_name, _jsonName, property) => { + this.updateIncludes(true, includes, property.type, defName); + }, + ); } if (includes.size !== 0) { @@ -2434,16 +3062,27 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { return; } - if (rec.typeKind === "class" || rec.typeKind === "union") { + if ( + rec.typeKind === "class" || + rec.typeKind === "union" + ) { if (this._options.codeFormat) { this.emitLine("class ", name, ";"); } else { this.emitLine("struct ", name, ";"); } } else if (rec.typeKind === "enum") { - this.emitLine("enum class ", name, " : ", this._enumType, ";"); + this.emitLine( + "enum class ", + name, + " : ", + this._enumType, + ";", + ); } else { - panic(`Invalid type "${rec.typeKind}" to forward declare`); + panic( + `Invalid type "${rec.typeKind}" to forward declare`, + ); } }); }); @@ -2453,7 +3092,10 @@ 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); @@ -2483,7 +3125,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.startFile("Generators.hpp", true); - this._allTypeNames.forEach(t => { + this._allTypeNames.forEach((t) => { this.emitInclude(false, [t, ".hpp"]); }); @@ -2503,7 +3145,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { }, (u, n) => { this.emitDefinition(u, n); - } + }, ); /** @@ -2517,7 +3159,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.startFile(proposedFilename); - this._generatedFiles.forEach(f => { + this._generatedFiles.forEach((f) => { this.emitInclude(false, f); }); @@ -2525,7 +3167,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, ); }); @@ -2538,28 +3180,36 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { /** Gather all the unique/custom types used by the schema */ this._allTypeNames.clear(); - this.forEachDeclaration("none", decl => { - const definedTypes = directlyReachableTypes(decl.type, t => { - if (isNamedType(t) && (t instanceof ClassType || t instanceof EnumType || t instanceof UnionType)) { - return new Set([ - this.sourcelikeToString( - this.cppType( - t, - { - needsForwardIndirection: false, - needsOptionalIndirection: false, - inJsonNamespace: false - }, - true, - false, - false - ) - ) - ]); - } + this.forEachDeclaration("none", (decl) => { + const definedTypes = directlyReachableTypes( + decl.type, + (t) => { + if ( + isNamedType(t) && + (t instanceof ClassType || + t instanceof EnumType || + t instanceof UnionType) + ) { + return new Set([ + this.sourcelikeToString( + this.cppType( + t, + { + needsForwardIndirection: false, + needsOptionalIndirection: false, + inJsonNamespace: false, + }, + true, + false, + false, + ), + ), + ]); + } - return null; - }); + return null; + }, + ); this._allTypeNames = setUnion(definedTypes, this._allTypeNames); }); @@ -2577,11 +3227,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, false, - false + false, ); const newType = this.cppType( @@ -2589,11 +3239,11 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { { needsForwardIndirection: true, needsOptionalIndirection: true, - inJsonNamespace: true + inJsonNamespace: true, }, false, true, - false + false, ); return originalType !== newType; @@ -2609,7 +3259,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { "", new WrappingCode(["std::to_string("], [")"]), "", - "" + "", ); } @@ -2617,7 +3267,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { _qualifier: Sourcelike[], _fromType: Sourcelike, _toType: Sourcelike, - inner: Sourcelike + inner: Sourcelike, ): Sourcelike { return inner; } @@ -2637,7 +3287,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { "L", new WrappingCode(["std::to_wstring("], [")"]), "Utf16_Utf8", - "convert" + "convert", ); } @@ -2645,9 +3295,12 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { qualifier: Sourcelike[], fromType: Sourcelike, toType: Sourcelike, - inner: Sourcelike + inner: Sourcelike, ): Sourcelike { - if (this.superThis.sourcelikeToString(fromType) === this.superThis.sourcelikeToString(toType)) { + if ( + this.superThis.sourcelikeToString(fromType) === + this.superThis.sourcelikeToString(toType) + ) { return inner; } @@ -2661,7 +3314,7 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this._encodingFunction, "(", inner, - ")" + ")", ]; } @@ -2670,100 +3323,144 @@ export class CPlusPlusRenderer extends ConvenienceRenderer { this.superThis.emitLine("struct tag {};"); this.superThis.ensureBlankLine(); - this.superThis.emitLine("template"); + this.superThis.emitLine( + "template", + ); this.superThis.emitBlock(["class Utf16_Utf8"], true, () => { this.superThis.emitLine("private:"); this.superThis.emitLine("template"); this.superThis.emitBlock( - ["static toType convert(tag >, tag >, fromType ptr)"], + [ + "static toType convert(tag >, tag >, fromType ptr)", + ], 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(); this.superThis.emitLine("template"); this.superThis.emitBlock( - ["static toType convert(tag >, tag >, fromType v)"], + [ + "static toType convert(tag >, tag >, fromType v)", + ], false, () => { this.superThis.emitLine("auto it = v.begin();"); - this.superThis.emitLine("auto newVector = std::vector();"); - this.superThis.emitBlock(["while (it != v.end())"], false, () => { - this.superThis.emitLine("newVector.push_back(Utf16_Utf8::convert(*it));"); - this.superThis.emitLine("it++;"); - }); + this.superThis.emitLine( + "auto newVector = std::vector();", + ); + this.superThis.emitBlock( + ["while (it != v.end())"], + false, + () => { + this.superThis.emitLine( + "newVector.push_back(Utf16_Utf8::convert(*it));", + ); + this.superThis.emitLine("it++;"); + }, + ); this.superThis.emitLine("return newVector;"); - } + }, ); this.superThis.ensureBlankLine(); - this.superThis.emitLine("template"); + this.superThis.emitLine( + "template", + ); this.superThis.emitBlock( - ["static toType convert(tag >, tag >, fromType m)"], + [ + "static toType convert(tag >, tag >, fromType m)", + ], false, () => { this.superThis.emitLine("auto it = m.begin();"); - 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)));" - ); - this.superThis.emitLine("it++;"); - }); + 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)));", + ); + this.superThis.emitLine("it++;"); + }, + ); this.superThis.emitLine("return newMap;"); - } + }, ); this.superThis.ensureBlankLine(); this.superThis.emitLine("template"); - this.superThis.emitBlock(["static fromType convert(tag, tag, fromType from)"], false, () => { - this.superThis.emitLine("return from;"); - }); - this.superThis.ensureBlankLine(); - this.superThis.emitBlock( - ["static std::wstring convert(tag, tag, std::string str)"], + [ + "static fromType convert(tag, tag, fromType from)", + ], false, () => { - this.superThis.emitLine( - "return std::wstring_convert, wchar_t>{}.from_bytes(str.data());" - ); - } + this.superThis.emitLine("return from;"); + }, ); this.superThis.ensureBlankLine(); this.superThis.emitBlock( - ["static std::string convert(tag, tag, std::wstring str)"], + [ + "static std::wstring convert(tag, tag, std::string str)", + ], false, () => { this.superThis.emitLine( - "return std::wstring_convert, wchar_t>{}.to_bytes(str.data());" + "return std::wstring_convert, wchar_t>{}.from_bytes(str.data());", ); - } + }, + ); + this.superThis.ensureBlankLine(); + + this.superThis.emitBlock( + [ + "static std::string convert(tag, tag, std::wstring str)", + ], + false, + () => { + this.superThis.emitLine( + "return std::wstring_convert, wchar_t>{}.to_bytes(str.data());", + ); + }, ); this.superThis.ensureBlankLine(); this.superThis.emitLine("public:"); - this.superThis.emitBlock(["static toType convert(fromType in)"], false, () => { - this.superThis.emitLine("return convert(tag(), tag(), in);"); - }); + this.superThis.emitBlock( + ["static toType convert(fromType in)"], + false, + () => { + this.superThis.emitLine( + "return convert(tag(), tag(), in);", + ); + }, + ); }); this.superThis.ensureBlankLine(); this.superThis.emitLine("template"); - this.superThis.emitBlock(["std::wstring wdump(const T& j)"], false, () => { - this.superThis.emitLine("std::ostringstream s;"); - this.superThis.emitLine("s << j;"); - this.superThis.emitLine( - "return ", - this.superThis.ourQualifier(false), - "Utf16_Utf8::convert(s.str()); " - ); - }); + this.superThis.emitBlock( + ["std::wstring wdump(const T& j)"], + false, + () => { + this.superThis.emitLine("std::ostringstream s;"); + this.superThis.emitLine("s << j;"); + this.superThis.emitLine( + "return ", + this.superThis.ourQualifier(false), + "Utf16_Utf8::convert(s.str()); ", + ); + }, + ); this.superThis.ensureBlankLine(); } })(this); diff --git a/packages/quicktype-core/src/language/CPlusPlus/constants.ts b/packages/quicktype-core/src/language/CPlusPlus/constants.ts index 4ed53bd8..a8872a1c 100644 --- a/packages/quicktype-core/src/language/CPlusPlus/constants.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/constants.ts @@ -1,103 +1,102 @@ - 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" + "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/language.ts b/packages/quicktype-core/src/language/CPlusPlus/language.ts index 730d5750..c040e2e2 100644 --- a/packages/quicktype-core/src/language/CPlusPlus/language.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/language.ts @@ -1,7 +1,12 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { CPlusPlusRenderer } from "./CPlusPlusRenderer"; @@ -12,7 +17,7 @@ const namingStyles = { "camel-case": "camel", "upper-underscore-case": "upper-underscore", "pascal-case-upper-acronyms": "pascal-upper-acronyms", - "camel-case-upper-acronyms": "camel-upper-acronyms" + "camel-case-upper-acronyms": "camel-upper-acronyms", } as const; export const cPlusPlusOptions = { @@ -21,70 +26,101 @@ export const cPlusPlusOptions = { "Source code generation type, whether to generate single or multiple source files", { "single-source": true, - "multi-source": false + "multi-source": false, } as const, "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, } as const, "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, } as const, - "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, } as const, - "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, } as const, - "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"), - enumType: new StringOption("enum-type", "Type of enum class", "NAME", "int", "secondary"), - typeNamingStyle: new EnumOption("type-style", "Naming style for types", namingStyles, "pascal-case"), - memberNamingStyle: new EnumOption("member-style", "Naming style for members", namingStyles, "underscore-case"), + 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", + namingStyles, + "pascal-case", + ), + memberNamingStyle: new EnumOption( + "member-style", + "Naming style for members", + namingStyles, + "underscore-case", + ), enumeratorNamingStyle: new EnumOption( "enumerator-style", "Naming style for enumerators", namingStyles, - "upper-underscore-case" + "upper-underscore-case", + ), + 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, ), - 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 const cPlusPlusLanguageConfig = { displayName: "C++", names: ["c++", "cpp", "cplusplus"], - extension: "cpp" + extension: "cpp", } as const; -export class CPlusPlusTargetLanguage extends TargetLanguage { +export class CPlusPlusTargetLanguage extends TargetLanguage< + typeof cPlusPlusLanguageConfig +> { public constructor() { super(cPlusPlusLanguageConfig); } @@ -101,7 +137,14 @@ export class CPlusPlusTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index 93c6e75d..51a7d66c 100644 --- a/packages/quicktype-core/src/language/CPlusPlus/utils.ts +++ b/packages/quicktype-core/src/language/CPlusPlus/utils.ts @@ -2,12 +2,16 @@ import { type MinMaxConstraint, minMaxLengthForType, minMaxValueForType, - patternForType + 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"; +import type { Name } from "../../Naming"; +import type { Sourcelike } from "../../Source"; +import { + isAscii, + isLetterOrUnderscoreOrDigit, + legalizeCharacters, +} from "../../support/Strings"; +import type { Type, TypeKind } from "../../Type"; export function constraintsForType(t: Type): | { @@ -19,11 +23,18 @@ export function constraintsForType(t: Type): const minMax = minMaxValueForType(t); const minMaxLength = minMaxLengthForType(t); const pattern = patternForType(t); - if (minMax === undefined && minMaxLength === undefined && pattern === undefined) return undefined; + if ( + minMax === undefined && + minMaxLength === undefined && + pattern === undefined + ) + return undefined; return { minMax, minMaxLength, pattern }; } -export const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); +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"; @@ -37,7 +48,7 @@ export const optionalFactoryAsSharedType = "std::make_shared"; */ export enum IncludeKind { ForwardDeclare = "ForwardDeclare", - Include = "Include" + Include = "Include", } // FIXME: make these string enums eventually @@ -49,7 +60,7 @@ export enum GlobalNames { ValueTooShortException = 5, ValueTooLongException = 6, InvalidPatternException = 7, - CheckConstraint = 8 + CheckConstraint = 8, } // FIXME: make these string enums eventually @@ -74,7 +85,7 @@ export enum MemberNames { SetMaxLength = 18, Pattern = 19, GetPattern = 20, - SetPattern = 21 + SetPattern = 21, } export interface ConstraintMember { @@ -121,12 +132,15 @@ export interface StringType { qualifier: Sourcelike[], fromType: Sourcelike, toType: Sourcelike, - inner: Sourcelike + inner: Sourcelike, ) => Sourcelike; wrapToString: (inner: Sourcelike) => Sourcelike; } -export function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): Sourcelike[] { +export function addQualifier( + qualifier: Sourcelike, + qualified: Sourcelike[], +): Sourcelike[] { if (qualified.length === 0) { return []; } @@ -137,7 +151,7 @@ export function addQualifier(qualifier: Sourcelike, qualified: Sourcelike[]): So export class WrappingCode { public constructor( private readonly start: Sourcelike[], - private readonly end: Sourcelike[] + private readonly end: Sourcelike[], ) {} public wrap(qualifier: Sourcelike, inner: Sourcelike): Sourcelike { @@ -170,7 +184,7 @@ export class BaseString { stringLiteralPrefix: string, toString: WrappingCode, encodingClass: string, - encodingFunction: string + encodingFunction: string, ) { this._stringType = stringType; this._constStringType = constStringType; diff --git a/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts index 0c655a5e..e2ec815b 100644 --- a/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts +++ b/packages/quicktype-core/src/language/CSharp/CSharpRenderer.ts @@ -1,41 +1,70 @@ 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 { + anyTypeIssueAnnotation, + nullTypeIssueAnnotation, +} from "../../Annotation"; +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, maybeAnnotated } from "../../Source"; import { assert } from "../../support/Support"; -import { type TargetLanguage } from "../../TargetLanguage"; +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 "../../Type/TypeUtils"; +import type { + ClassProperty, + ClassType, + EnumType, + Type, + UnionType, +} from "../../Type"; +import { + directlyReachableSingleNamedType, + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; -import { type cSharpOptions } from "./language"; +import type { cSharpOptions } from "./language"; import { AccessModifier, csTypeForTransformedStringType, isValueType, namingFunction, namingFunctionKeep, - noFollow + noFollow, } from "./utils"; export class CSharpRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _csOptions: OptionValues + private readonly _csOptions: OptionValues, ) { super(targetLanguage, renderContext); } protected forbiddenNamesForGlobalNamespace(): string[] { - return ["QuickType", "Type", "System", "Console", "Exception", "DateTimeOffset", "Guid", "Uri"]; + return [ + "QuickType", + "Type", + "System", + "Console", + "Exception", + "DateTimeOffset", + "Guid", + "Uri", + ]; } - protected forbiddenForObjectProperties(_: ClassType, classNamed: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties( + _: ClassType, + classNamed: Name, + ): ForbiddenWordsInfo { return { names: [ classNamed, @@ -45,13 +74,16 @@ 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 }; } @@ -60,7 +92,9 @@ export class CSharpRenderer extends ConvenienceRenderer { } protected namerForObjectProperty(): Namer { - return this._csOptions.keepPropertyName ? namingFunctionKeep : namingFunction; + return this._csOptions.keepPropertyName + ? namingFunctionKeep + : namingFunction; } protected makeUnionMemberNamer(): Namer { @@ -92,37 +126,65 @@ export class CSharpRenderer extends ConvenienceRenderer { 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, - _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); + (_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 => { + (classType) => this.nameForNamedType(classType), + (mapType) => [ + "Dictionary", + ], + (enumType) => this.nameForNamedType(enumType), + (unionType) => { const nullable = nullableFromUnion(unionType); - if (nullable !== null) return this.nullableCSType(nullable, noFollow); + 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)) { @@ -142,7 +204,7 @@ export class CSharpRenderer extends ConvenienceRenderer { declaration: Sourcelike, name: Sourcelike, baseclass: Sourcelike | undefined, - emitter: () => void + emitter: () => void, ): void { switch (accessModifier) { case AccessModifier.Public: @@ -169,12 +231,17 @@ export class CSharpRenderer extends ConvenienceRenderer { _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) @@ -192,7 +259,11 @@ export class CSharpRenderer extends ConvenienceRenderer { if (this._csOptions.dense) { this.emitLine(start, lines.join("; "), ""); } else { - this.emitCommentLines(lines, { lineStart: "/// ", beforeComment: start, afterComment: "/// " }); + this.emitCommentLines(lines, { + lineStart: "/// ", + beforeComment: start, + afterComment: "/// ", + }); } } @@ -209,45 +280,71 @@ export class CSharpRenderer extends ConvenienceRenderer { this.baseclassForType(c), () => { if (c.getProperties().size === 0) return; - const blankLines = this.blankLinesBetweenAttributes() ? "interposing" : "none"; - let columns: Sourcelike[][] = []; + const blankLines = this.blankLinesBetweenAttributes() + ? "interposing" + : "none"; + const 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.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 ) { - this.ensureBlankLine(); + 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); } - 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; - }); + isFirstProperty = false; + previousDescription = description; + }, + ); if (columns.length > 0) { this.emitTable(columns); } - } + }, ); } @@ -260,32 +357,63 @@ export class CSharpRenderer extends ConvenienceRenderer { unionName, this.baseclassForType(u), () => { - this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { - const csType = this.nullableCSType(t); - this.emitLine("public ", csType, " ", fieldName, ";"); - }); + 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" - ]); + 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, " }"] - ); - }); + 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); - } + this.emitExpressionMember( + "public bool IsNull", + arrayIntercalate(" && ", nullTests), + true, + ); + }, ); } private emitEnumDefinition(e: EnumType, enumName: Name): void { const caseNames: Sourcelike[] = []; - this.forEachEnumCase(e, "none", name => { + this.forEachEnumCase(e, "none", (name) => { if (caseNames.length > 0) caseNames.push(", "); caseNames.push(name); }); @@ -293,7 +421,11 @@ 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(() => { @@ -315,7 +447,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) { @@ -348,9 +480,16 @@ export class CSharpRenderer extends ConvenienceRenderer { } 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.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(); } diff --git a/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts index 7e89da0a..df9e1a6a 100644 --- a/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts +++ b/packages/quicktype-core/src/language/CSharp/NewtonSoftCSharpRenderer.ts @@ -1,13 +1,16 @@ import { arrayIntercalate } from "collection-utils"; -import { type ForbiddenWordsInfo, inferredNameOrder } from "../../ConvenienceRenderer"; +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 { 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 type { TargetLanguage } from "../../TargetLanguage"; import { ArrayDecodingTransformer, ArrayEncodingTransformer, @@ -26,13 +29,20 @@ import { UnionInstantiationTransformer, UnionMemberMatchTransformer, followTargetType, - transformationForType + transformationForType, } from "../../Transformers"; -import { ArrayType, type ClassProperty, ClassType, EnumType, type Type, UnionType } from "../../Type"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + type Type, + UnionType, +} from "../../Type"; import { nullableFromUnion } from "../../Type/TypeUtils"; import { CSharpRenderer } from "./CSharpRenderer"; -import { type newtonsoftCSharpOptions } from "./language"; +import type { newtonsoftCSharpOptions } from "./language"; import { AccessModifier, alwaysApplyTransformation, @@ -40,7 +50,7 @@ import { denseNullValueHandlingEnumName, denseRequiredEnumName, isValueType, - namingFunction + namingFunction, } from "./utils"; export class NewtonsoftCSharpRenderer extends CSharpRenderer { @@ -55,7 +65,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext, _options); this._needHelpers = _options.features.helpers; @@ -75,7 +85,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { "MetadataPropertyHandling", "DateParseHandling", "FromJson", - "Required" + "Required", ]; if (this._options.dense) { forbidden.push("J", "R", "N"); @@ -88,32 +98,52 @@ 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) { + if ( + xfer instanceof DecodingTransformer && + xfer.consumer !== undefined + ) { xfer = xfer.consumer; } - return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); + return new SimpleName( + [`${xfer.kind}_converter`], + namingFunction, + inferredNameOrder + 30, + ); } - return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); + 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]; @@ -126,14 +156,27 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { super.emitUsings(); this.ensureBlankLine(); - for (const ns of ["System.Globalization", "Newtonsoft.Json", "Newtonsoft.Json.Converters"]) { + 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"]); + this.emitUsing([ + denseJsonPropertyName, + " = Newtonsoft.Json.JsonPropertyAttribute", + ]); + this.emitUsing([ + denseRequiredEnumName, + " = Newtonsoft.Json.Required", + ]); + this.emitUsing([ + denseNullValueHandlingEnumName, + " = Newtonsoft.Json.NullValueHandling", + ]); } if (this._options.baseclass === "EntityData") { @@ -153,7 +196,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, ";"); @@ -161,12 +204,22 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.forEachTopLevel("none", (t, topLevelName) => { let rhs: Sourcelike; if (t instanceof EnumType) { - rhs = ["JsonConvert.DeserializeObject<", topLevelName, ">(jsonString)"]; + rhs = [ + "JsonConvert.DeserializeObject<", + topLevelName, + ">(jsonString)", + ]; } else { rhs = [topLevelName, ".FromJson(jsonString)"]; } - this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); + this.emitLine( + "// var ", + modifySource(camelCase, topLevelName), + " = ", + rhs, + ";", + ); }); } @@ -192,32 +245,56 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { property: ClassProperty, _name: Name, _c: ClassType, - jsonName: string + jsonName: string, ): Sourcelike[] | undefined { if (!this._needAttributes) return undefined; const attributes: Sourcelike[] = []; - const jsonProperty = this._options.dense ? denseJsonPropertyName : "JsonProperty"; + 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 nullValueHandlingClass = this._options.dense + ? "N" + : "NullValueHandling"; const nullValueHandling = - isOptional && !isNullable ? [", NullValueHandling = ", nullValueHandlingClass, ".Ignore"] : []; + 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]; + required = [ + ", Required = ", + requiredClass, + ".DisallowNull", + nullValueHandling, + ]; } else if (!isOptional && isNullable) { required = [", Required = ", requiredClass, ".AllowNull"]; } else { - required = [", Required = ", requiredClass, ".Always", nullValueHandling]; + required = [ + ", Required = ", + requiredClass, + ".Always", + nullValueHandling, + ]; } - attributes.push(["[", jsonProperty, '("', escapedName, '"', required, ")]"]); + attributes.push([ + "[", + jsonProperty, + '("', + escapedName, + '"', + required, + ")]", + ]); const converter = this.converterForType(property.type); if (converter !== undefined) { @@ -233,7 +310,9 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { // 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); + return t.kind === "any" || t.kind === "none" + ? "object" + : this.csType(t); } private emitFromJsonForTopLevel(t: Type, name: Name): void { @@ -251,13 +330,26 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } 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)"] - ); - }); + 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 { @@ -283,30 +375,48 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { 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)"] - ); - } - }); - }); + 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); + 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)" + "public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)", ); this.emitBlock(emitBody); } @@ -315,7 +425,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { this.emitLine( "public override void WriteJson(JsonWriter writer, object ", variable, - ", JsonSerializer serializer)" + ", JsonSerializer serializer)", ); this.emitBlock(emitBody); } @@ -328,25 +438,48 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { 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.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); - }); + this.emitLine( + "new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }", + ); + }); + this.emitLine("},"); + }, true); + }, + ); } private emitDecoderTransformerCase( @@ -354,7 +487,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { variableName: string, xfer: Transformer | undefined, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): void { if (xfer === undefined) return; @@ -363,7 +496,12 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } this.indent(() => { - const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); + const allHandled = this.emitDecodeTransformer( + xfer, + targetType, + emitFinish, + variableName, + ); if (!allHandled) { this.emitLine("break;"); } @@ -374,28 +512,32 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { value: Sourcelike, consumer: Transformer | undefined, targetType: Type, - emitFinish: (variableName: Sourcelike) => void + emitFinish: (variableName: Sourcelike) => void, ): boolean { if (consumer === undefined) { emitFinish(value); return true; - } else { - return this.emitTransformer(value, consumer, targetType, emitFinish); } + + return this.emitTransformer(value, consumer, targetType, emitFinish); } private emitDecodeTransformer( xfer: Transformer, targetType: Type, emitFinish: (value: Sourcelike) => void, - variableName = "value" + 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 converter = ", + this.converterObject(converter), + ";", + ); this.emitLine( "var ", variableName, @@ -403,15 +545,29 @@ 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)), ";"); + const 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) { + return this.emitConsume( + variableName, + xfer.consumer, + targetType, + emitFinish, + ); + } + + if (xfer instanceof ArrayDecodingTransformer) { // FIXME: Consume StartArray if (!(targetType instanceof ArrayType)) { return panic("Array decoding must produce an array type"); @@ -419,14 +575,20 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { // FIXME: handle EOF this.emitLine("reader.Read();"); - this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); + 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" + (v) => this.emitLine(variableName, ".Add(", v, ");"), + "arrayItem", ); // FIXME: handle EOF this.emitLine("reader.Read();"); @@ -438,13 +600,20 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { emitFinish(result); return true; - } else if (xfer instanceof DecodingChoiceTransformer) { + } + + 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"); + const allHandled = this.emitDecodeTransformer( + nullTransformer, + targetType, + emitFinish, + "null", + ); if (!allHandled) { this.emitLine("break"); } @@ -456,49 +625,62 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { "integerValue", xfer.integerTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( - xfer.integerTransformer === undefined ? ["Integer", "Float"] : ["Float"], + xfer.integerTransformer === undefined + ? ["Integer", "Float"] + : ["Float"], "doubleValue", xfer.doubleTransformer, targetType, - emitFinish + emitFinish, + ); + this.emitDecoderTransformerCase( + ["Boolean"], + "boolValue", + xfer.boolTransformer, + targetType, + emitFinish, ); - this.emitDecoderTransformerCase(["Boolean"], "boolValue", xfer.boolTransformer, targetType, emitFinish); this.emitDecoderTransformerCase( ["String", "Date"], "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; - } else { - return panic("Unknown transformer"); } + + 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)]; + } + if (t instanceof EnumType) { + return [ + this.nameForNamedType(t), + ".", + this.nameForEnumCase(t, stringCase), + ]; } return panic(`Type ${t.kind} does not have string cases`); @@ -508,7 +690,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { variable: Sourcelike, xfer: Transformer, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): boolean { function directTargetType(continuation: Transformer | undefined): Type { if (continuation === undefined) { @@ -520,14 +702,19 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { if (xfer instanceof ChoiceTransformer) { const caseXfers = xfer.transformers; - if (caseXfers.length > 1 && caseXfers.every(caseXfer => caseXfer instanceof StringMatchTransformer)) { + 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 + matchXfer.stringCase, ); this.emitLine("case ", value, ":"); this.indent(() => { @@ -535,7 +722,7 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { variable, matchXfer.transformer, targetType, - emitFinish + emitFinish, ); if (!allDone) { this.emitLine("break;"); @@ -545,10 +732,15 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { }); // 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); - } + } + + for (const caseXfer of caseXfers) { + this.emitTransformer( + variable, + caseXfer, + targetType, + emitFinish, + ); } } else if (xfer instanceof UnionMemberMatchTransformer) { const memberType = xfer.memberType; @@ -567,7 +759,10 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { test = [variable, ".IsNull"]; member = "null"; } else { - const memberName = this.nameForUnionMember(xfer.sourceType, memberType); + const memberName = this.nameForUnionMember( + xfer.sourceType, + memberType, + ); member = [variable, ".", memberName]; test = [member, " != null"]; } @@ -577,16 +772,41 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } this.emitLine("if (", test, ")"); - this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); + this.emitBlock(() => + this.emitTransformer( + member, + xfer.transformer, + targetType, + emitFinish, + ), + ); } else if (xfer instanceof StringMatchTransformer) { - const value = this.stringCaseValue(followTargetType(xfer.sourceType), xfer.stringCase); + const value = this.stringCaseValue( + followTargetType(xfer.sourceType), + xfer.stringCase, + ); this.emitLine("if (", variable, " == ", value, ")"); - this.emitBlock(() => this.emitTransformer(variable, xfer.transformer, targetType, emitFinish)); + 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);"); + this.emitLine( + "var converter = ", + this.converterObject(converter), + ";", + ); + this.emitLine( + "converter.WriteJson(writer, ", + variable, + ", serializer);", + ); } else { this.emitLine(this.serializeValueCode(variable), ";"); } @@ -598,75 +818,160 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { const itemVariable = "arrayItem"; this.emitLine("foreach (var ", itemVariable, " in ", variable, ")"); this.emitBlock(() => { - this.emitTransformer(itemVariable, xfer.itemTransformer, xfer.itemTargetType, () => { - return; - }); + 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; + 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)); + 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)); + 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.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)); + 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)); + 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`); + 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)'], + [ + 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); + 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); + this.emitLine( + "var boolString = ", + variable, + ' ? "true" : "false";', + ); + return this.emitConsume( + "boolString", + xfer.consumer, + targetType, + emitFinish, + ); default: - return panic(`Stringifying ${xfer.sourceType.kind} not supported`); + 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); + 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; @@ -681,7 +986,14 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + this.emitBlock(() => + this.emitConsume( + variable, + xfer.consumer, + targetType, + emitFinish, + ), + ); return false; } else if (xfer instanceof MinMaxValueTransformer) { const min = xfer.minimum; @@ -697,11 +1009,20 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { } this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + 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"); + return panic( + "Union instantiation transformer must produce a union type", + ); } const maybeNullable = nullableFromUnion(targetType); @@ -713,7 +1034,10 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { if (xfer.sourceType.kind === "null") { initializer = " "; } else { - const memberName = this.nameForUnionMember(targetType, xfer.sourceType); + const memberName = this.nameForUnionMember( + targetType, + xfer.sourceType, + ); initializer = [" ", memberName, " = ", variable, " "]; } @@ -733,67 +1057,107 @@ export class NewtonsoftCSharpRenderer extends CSharpRenderer { 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;"); + 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, + "?)", + ]; } - 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.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;", + ); + } - this.emitLine("var value = (", csType, ")untypedValue;"); - const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;") + 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, + "();", ); - 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.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)); + this.forEachTransformation("leading-and-interposing", (n, t) => + this.emitTransformation(n, t), + ); } } diff --git a/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts b/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts index 29c3e973..fc5a205e 100644 --- a/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts +++ b/packages/quicktype-core/src/language/CSharp/SystemTextJsonCSharpRenderer.ts @@ -1,13 +1,16 @@ import { arrayIntercalate } from "collection-utils"; -import { type ForbiddenWordsInfo, inferredNameOrder } from "../../ConvenienceRenderer"; +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 { 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 type { TargetLanguage } from "../../TargetLanguage"; import { ArrayDecodingTransformer, ArrayEncodingTransformer, @@ -26,20 +29,27 @@ import { UnionInstantiationTransformer, UnionMemberMatchTransformer, followTargetType, - transformationForType + transformationForType, } from "../../Transformers"; -import { ArrayType, type ClassProperty, ClassType, EnumType, type Type, UnionType } from "../../Type"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + type Type, + UnionType, +} from "../../Type"; import { nullableFromUnion } from "../../Type/TypeUtils"; import { CSharpRenderer } from "./CSharpRenderer"; -import { type systemTextJsonCSharpOptions } from "./language"; +import type { systemTextJsonCSharpOptions } from "./language"; import { AccessModifier, alwaysApplyTransformation, denseJsonPropertyName, denseNullValueHandlingEnumName, isValueType, - namingFunction + namingFunction, } from "./utils"; export class SystemTextJsonCSharpRenderer extends CSharpRenderer { @@ -54,7 +64,9 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues< + typeof systemTextJsonCSharpOptions + >, ) { super(targetLanguage, renderContext, _options); this._needHelpers = _options.features.helpers; @@ -75,7 +87,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // "MetadataPropertyHandling", // "DateParseHandling", "FromJson", - "Required" + "Required", ]; if (this._options.dense) { forbidden.push("J", "R", "N"); @@ -88,32 +100,52 @@ 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) { + if ( + xfer instanceof DecodingTransformer && + xfer.consumer !== undefined + ) { xfer = xfer.consumer; } - return new SimpleName([`${xfer.kind}_converter`], namingFunction, inferredNameOrder + 30); + return new SimpleName( + [`${xfer.kind}_converter`], + namingFunction, + inferredNameOrder + 30, + ); } - return new DependencyName(namingFunction, typeName.order + 30, lookup => `${lookup(typeName)}_converter`); + 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]; @@ -126,14 +158,24 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { super.emitUsings(); this.ensureBlankLine(); - for (const ns of ["System.Text.Json", "System.Text.Json.Serialization", "System.Globalization"]) { + 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([ + denseJsonPropertyName, + " = System.Text.Json.Serialization.JsonPropertyNameAttribute", + ]); // this.emitUsing([denseRequiredEnumName, " = Newtonsoft.Json.Required"]); - this.emitUsing([denseNullValueHandlingEnumName, " = System.Text.Json.Serialization.JsonIgnoreCondition"]); + this.emitUsing([ + denseNullValueHandlingEnumName, + " = System.Text.Json.Serialization.JsonIgnoreCondition", + ]); } if (this._options.baseclass === "EntityData") { @@ -161,7 +203,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, ";"); @@ -169,12 +211,22 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { this.forEachTopLevel("none", (t, topLevelName) => { let rhs: Sourcelike; if (t instanceof EnumType) { - rhs = ["JsonSerializer.Deserialize<", topLevelName, ">(jsonString)"]; + rhs = [ + "JsonSerializer.Deserialize<", + topLevelName, + ">(jsonString)", + ]; } else { rhs = [topLevelName, ".FromJson(jsonString)"]; } - this.emitLine("// var ", modifySource(camelCase, topLevelName), " = ", rhs, ";"); + this.emitLine( + "// var ", + modifySource(camelCase, topLevelName), + " = ", + rhs, + ";", + ); }); // fix: should this be an option? Or respond to an existing option? @@ -206,19 +258,25 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { property: ClassProperty, _name: Name, _c: ClassType, - jsonName: string + jsonName: string, ): Sourcelike[] | undefined { if (!this._needAttributes) return undefined; const attributes: Sourcelike[] = []; - const jsonPropertyName = this._options.dense ? denseJsonPropertyName : "JsonPropertyName"; + 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)]"]); + attributes.push([ + "[", + "JsonIgnore", + "(Condition = JsonIgnoreCondition.WhenWritingNull)]", + ]); } // const requiredClass = this._options.dense ? "R" : "Required"; @@ -251,7 +309,9 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // 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); + return t.kind === "any" || t.kind === "none" + ? "object" + : this.csType(t); } private emitFromJsonForTopLevel(t: Type, name: Name): void { @@ -269,13 +329,26 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } 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)"] - ); - }); + 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 { @@ -304,54 +377,83 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { case "string": return ["reader.GetString()"]; default: - return ["JsonSerializer.Deserialize<", typeName, ">(ref reader, options)"]; + 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()"]; + if (value !== "null") { + return ["JsonSerializer.Serialize(writer, ", value, ", options)"]; + } + + 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)"] - ); - } - }); - }); + 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); + 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)" + " 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); } @@ -364,31 +466,46 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { 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.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); - }); + this.emitLine("new DateOnlyConverter(),"); + this.emitLine("new TimeOnlyConverter(),"); + this.emitLine("IsoDateTimeOffsetConverter.Singleton"); + // this.emitLine("new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }"); + }); + this.emitLine("},"); + }, true); + }, + ); } private emitDecoderTransformerCase( @@ -396,7 +513,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { variableName: string, xfer: Transformer | undefined, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): void { if (xfer === undefined) return; @@ -405,7 +522,12 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } this.indent(() => { - const allHandled = this.emitDecodeTransformer(xfer, targetType, emitFinish, variableName); + const allHandled = this.emitDecodeTransformer( + xfer, + targetType, + emitFinish, + variableName, + ); if (!allHandled) { this.emitLine("break;"); } @@ -416,28 +538,32 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { value: Sourcelike, consumer: Transformer | undefined, targetType: Type, - emitFinish: (variableName: Sourcelike) => void + emitFinish: (variableName: Sourcelike) => void, ): boolean { if (consumer === undefined) { emitFinish(value); return true; - } else { - return this.emitTransformer(value, consumer, targetType, emitFinish); } + + return this.emitTransformer(value, consumer, targetType, emitFinish); } private emitDecodeTransformer( xfer: Transformer, targetType: Type, emitFinish: (value: Sourcelike) => void, - variableName = "value" + 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 converter = ", + this.converterObject(converter), + ";", + ); this.emitLine( "var ", variableName, @@ -445,15 +571,29 @@ 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)), ";"); + const 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) { + return this.emitConsume( + variableName, + xfer.consumer, + targetType, + emitFinish, + ); + } + + if (xfer instanceof ArrayDecodingTransformer) { // FIXME: Consume StartArray if (!(targetType instanceof ArrayType)) { return panic("Array decoding must produce an array type"); @@ -461,14 +601,20 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // FIXME: handle EOF this.emitLine("reader.Read();"); - this.emitLine("var ", variableName, " = new List<", this.csType(targetType.items), ">();"); + 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" + (v) => this.emitLine(variableName, ".Add(", v, ");"), + "arrayItem", ); // FIXME: handle EOF this.emitLine("reader.Read();"); @@ -480,13 +626,20 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { emitFinish(result); return true; - } else if (xfer instanceof DecodingChoiceTransformer) { + } + + 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"); + const allHandled = this.emitDecodeTransformer( + nullTransformer, + targetType, + emitFinish, + "null", + ); if (!allHandled) { this.emitLine("break"); } @@ -498,7 +651,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { "integerValue", xfer.integerTransformer, targetType, - emitFinish + emitFinish, ); this.emitDecoderTransformerCase( ["Number"], @@ -506,14 +659,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"], @@ -521,34 +674,39 @@ 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; - } else { - return panic("Unknown transformer"); } + + 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)]; + } + if (t instanceof EnumType) { + return [ + this.nameForNamedType(t), + ".", + this.nameForEnumCase(t, stringCase), + ]; } return panic(`Type ${t.kind} does not have string cases`); @@ -558,7 +716,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { variable: Sourcelike, xfer: Transformer, targetType: Type, - emitFinish: (value: Sourcelike) => void + emitFinish: (value: Sourcelike) => void, ): boolean { function directTargetType(continuation: Transformer | undefined): Type { if (continuation === undefined) { @@ -570,14 +728,19 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { if (xfer instanceof ChoiceTransformer) { const caseXfers = xfer.transformers; - if (caseXfers.length > 1 && caseXfers.every(caseXfer => caseXfer instanceof StringMatchTransformer)) { + 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 + matchXfer.stringCase, ); this.emitLine("case ", value, ":"); this.indent(() => { @@ -585,7 +748,7 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { variable, matchXfer.transformer, targetType, - emitFinish + emitFinish, ); if (!allDone) { this.emitLine("break;"); @@ -595,10 +758,15 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { }); // 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); - } + } + + for (const caseXfer of caseXfers) { + this.emitTransformer( + variable, + caseXfer, + targetType, + emitFinish, + ); } } else if (xfer instanceof UnionMemberMatchTransformer) { const memberType = xfer.memberType; @@ -617,7 +785,10 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { test = [variable, ".IsNull"]; member = "null"; } else { - const memberName = this.nameForUnionMember(xfer.sourceType, memberType); + const memberName = this.nameForUnionMember( + xfer.sourceType, + memberType, + ); member = [variable, ".", memberName]; test = [member, " != null"]; } @@ -627,16 +798,41 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } this.emitLine("if (", test, ")"); - this.emitBlock(() => this.emitTransformer(member, xfer.transformer, targetType, emitFinish)); + this.emitBlock(() => + this.emitTransformer( + member, + xfer.transformer, + targetType, + emitFinish, + ), + ); } else if (xfer instanceof StringMatchTransformer) { - const value = this.stringCaseValue(followTargetType(xfer.sourceType), xfer.stringCase); + const value = this.stringCaseValue( + followTargetType(xfer.sourceType), + xfer.stringCase, + ); this.emitLine("if (", variable, " == ", value, ")"); - this.emitBlock(() => this.emitTransformer(variable, xfer.transformer, targetType, emitFinish)); + 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);"); + this.emitLine( + "var converter = ", + this.converterObject(converter), + ";", + ); + this.emitLine( + "converter.WriteJson(writer, ", + variable, + ", serializer);", + ); } else { this.emitLine(this.serializeValueCode(variable), ";"); } @@ -648,25 +844,55 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { const itemVariable = "arrayItem"; this.emitLine("foreach (var ", itemVariable, " in ", variable, ")"); this.emitBlock(() => { - this.emitTransformer(itemVariable, xfer.itemTransformer, xfer.itemTargetType, () => { - return; - }); + 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; + 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)); + 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)); + this.emitLine( + "if (Guid.TryParse(", + variable, + ", out guid))", + ); + this.emitBlock(() => + this.emitConsume( + "guid", + xfer.consumer, + targetType, + emitFinish, + ), + ); break; case "uri": this.emitLine("try"); @@ -674,55 +900,112 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // 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.emitLine( + "if (!string.IsNullOrEmpty(stringValue))", + ); this.emitBlock(() => { this.emitLine("uri = new Uri(", variable, ");"); }); - this.emitConsume("uri", xfer.consumer, targetType, emitFinish); + 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)); + 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)); + 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`); + 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)'], + [ + 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); + 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); + this.emitLine( + "var boolString = ", + variable, + ' ? "true" : "false";', + ); + return this.emitConsume( + "boolString", + xfer.consumer, + targetType, + emitFinish, + ); default: - return panic(`Stringifying ${xfer.sourceType.kind} not supported`); + 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); + 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; @@ -737,7 +1020,14 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + this.emitBlock(() => + this.emitConsume( + variable, + xfer.consumer, + targetType, + emitFinish, + ), + ); return false; } else if (xfer instanceof MinMaxValueTransformer) { const min = xfer.minimum; @@ -753,11 +1043,20 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { } this.emitLine("if (", arrayIntercalate([" && "], conditions), ")"); - this.emitBlock(() => this.emitConsume(variable, xfer.consumer, targetType, emitFinish)); + 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"); + return panic( + "Union instantiation transformer must produce a union type", + ); } const maybeNullable = nullableFromUnion(targetType); @@ -769,7 +1068,10 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { if (xfer.sourceType.kind === "null") { initializer = " "; } else { - const memberName = this.nameForUnionMember(targetType, xfer.sourceType); + const memberName = this.nameForUnionMember( + targetType, + xfer.sourceType, + ); initializer = [" ", memberName, " = ", variable, " "]; } @@ -803,7 +1105,11 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { converterName, ["JsonConverter<", csType, ">"], () => { - let canConvertExpr: Sourcelike = ["t == typeof(", csType, ")"]; + const canConvertExpr: Sourcelike = [ + "t == typeof(", + csType, + ")", + ]; this.emitCanConvert(canConvertExpr); this.ensureBlankLine(); this.emitReadJson(() => { @@ -817,11 +1123,17 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // this.emitLine("if (reader.TokenType == JsonTokenType.Null) return null;"); // } - const allHandled = this.emitDecodeTransformer(xfer, targetType, v => - this.emitLine("return ", v, ";") + 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, + '"', + ]); } }, csType); this.ensureBlankLine(); @@ -837,32 +1149,52 @@ export class SystemTextJsonCSharpRenderer extends CSharpRenderer { // }); // } - const allHandled = this.emitTransformer("value", reverse.transformer, reverse.targetType, () => - this.emitLine("return;") + const allHandled = this.emitTransformer( + "value", + reverse.transformer, + reverse.targetType, + () => 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, "();"); - } + 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.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)); + this.forEachTransformation("leading-and-interposing", (n, t) => + this.emitTransformation(n, t), + ); this.emitMultiline(` public class DateOnlyConverter : JsonConverter { diff --git a/packages/quicktype-core/src/language/CSharp/constants.ts b/packages/quicktype-core/src/language/CSharp/constants.ts index bbe7f3df..0fafc49e 100644 --- a/packages/quicktype-core/src/language/CSharp/constants.ts +++ b/packages/quicktype-core/src/language/CSharp/constants.ts @@ -1,79 +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" + "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 index c9f7c6d8..83dd8afd 100644 --- a/packages/quicktype-core/src/language/CSharp/index.ts +++ b/packages/quicktype-core/src/language/CSharp/index.ts @@ -1,4 +1,9 @@ -export { CSharpTargetLanguage, cSharpOptions, newtonsoftCSharpOptions, systemTextJsonCSharpOptions } from "./language"; +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 index 6337ab39..79562aa2 100644 --- a/packages/quicktype-core/src/language/CSharp/language.ts +++ b/packages/quicktype-core/src/language/CSharp/language.ts @@ -1,11 +1,20 @@ -import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + 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 "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, + Type, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } from "../../types"; import { NewtonsoftCSharpRenderer } from "./NewtonSoftCSharpRenderer"; import { SystemTextJsonCSharpRenderer } from "./SystemTextJsonCSharpRenderer"; @@ -24,40 +33,45 @@ export const cSharpOptions = { "Serialization framework", { NewtonSoft: "NewtonSoft", - SystemTextJson: "SystemTextJson" + SystemTextJson: "SystemTextJson", } as const, - "NewtonSoft" + "NewtonSoft", ), useList: new EnumOption( "array-type", "Use T[] or List", { array: false, - list: true + list: true, }, - "array" + "array", ), dense: new EnumOption( "density", "Property density", { normal: false, - dense: true + dense: true, } as const, "normal", - "secondary" + "secondary", ), // FIXME: Do this via a configurable named eventually. - namespace: new StringOption("namespace", "Generated namespace", "NAME", "QuickType"), + namespace: new StringOption( + "namespace", + "Generated namespace", + "NAME", + "QuickType", + ), version: new EnumOption( "csharp-version", "C# version", { "5": 5, - "6": 6 + "6": 6, } as const, "6", - "secondary" + "secondary", ), virtual: new BooleanOption("virtual", "Generate virtual properties", false), typeForAny: new EnumOption( @@ -65,53 +79,79 @@ export const cSharpOptions = { 'Type to use for "any"', { object: "object", - dynamic: "dynamic" + dynamic: "dynamic", } as const, "object", - "secondary" + "secondary", ), useDecimal: new EnumOption( "number-type", "Type to use for numbers", { double: false, - decimal: true + decimal: true, } as const, "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 } + 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, + }, } as const, - "complete" + "complete", ), baseclass: new EnumOption( "base-class", "Base class", { EntityData: "EntityData", - Object: undefined + Object: undefined, } as const, "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, ), - checkRequired: new BooleanOption("check-required", "Fail if required properties are missing", false), - keepPropertyName: new BooleanOption("keep-property-name", "Keep original field name generate", false) } as const; export const newtonsoftCSharpOptions = Object.assign({}, cSharpOptions, {}); export const systemTextJsonCSharpOptions = Object.assign({}, cSharpOptions, {}); -export const cSharpLanguageConfig = { displayName: "C#", names: ["cs", "csharp"], extension: "cs" } as const; +export const cSharpLanguageConfig = { + displayName: "C#", + names: ["cs", "csharp"], + extension: "cs", +} as const; -export class CSharpTargetLanguage extends TargetLanguage { +export class CSharpTargetLanguage extends TargetLanguage< + typeof cSharpLanguageConfig +> { public constructor() { super(cSharpLanguageConfig); } @@ -121,7 +161,8 @@ export class CSharpTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); mapping.set("date", "date-time"); mapping.set("time", "date-time"); mapping.set("date-time", "date-time"); @@ -145,7 +186,10 @@ export class CSharpTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): ConvenienceRenderer { const options = getOptionValues(cSharpOptions, untypedOptionValues); switch (options.framework) { @@ -153,13 +197,19 @@ export class CSharpTargetLanguage extends TargetLanguage x, - x => x, - x => x, - x => x, + (x) => x, + (x) => x, + (x) => x, + (x) => x, "", - isStartCharacter + isStartCharacter, ); // @ts-expect-error needs strong type - return keywords.includes(result) ? "@" + result : result; + return keywords.includes(result) ? `@${result}` : result; } export function isValueType(t: Type): boolean { @@ -143,5 +158,7 @@ export function isValueType(t: Type): boolean { return nullableFromUnion(t) === null; } - return ["integer", "double", "bool", "enum", "date-time", "uuid"].includes(t.kind); + return ["integer", "double", "bool", "enum", "date-time", "uuid"].includes( + t.kind, + ); } diff --git a/packages/quicktype-core/src/language/Crystal/CrystalRenderer.ts b/packages/quicktype-core/src/language/Crystal/CrystalRenderer.ts index cb97ede7..80b27fe5 100644 --- a/packages/quicktype-core/src/language/Crystal/CrystalRenderer.ts +++ b/packages/quicktype-core/src/language/Crystal/CrystalRenderer.ts @@ -1,17 +1,39 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; -import { type Name, type Namer } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; +import { + anyTypeIssueAnnotation, + nullTypeIssueAnnotation, +} from "../../Annotation"; +import { + ConvenienceRenderer, + type ForbiddenWordsInfo, +} from "../../ConvenienceRenderer"; +import type { Name, 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 "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import type { + ClassType, + EnumType, + Type, + UnionType, +} from "../../Type"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { camelNamingFunction, crystalStringEscape, snakeNamingFunction } from "./utils"; +import { + camelNamingFunction, + crystalStringEscape, + snakeNamingFunction, +} from "./utils"; export class CrystalRenderer extends ConvenienceRenderer { - public constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) { + public constructor( + targetLanguage: TargetLanguage, + renderContext: RenderContext, + ) { super(targetLanguage, renderContext); } @@ -35,15 +57,24 @@ export class CrystalRenderer extends ConvenienceRenderer { 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 }; } @@ -63,27 +94,42 @@ export class CrystalRenderer extends ConvenienceRenderer { private crystalType(t: Type, withIssues = false): Sourcelike { return matchType( t, - _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "JSON::Any?"), - _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, "Nil"), - _boolType => "Bool", - _integerType => "Int32", - _doubleType => "Float64", - _stringType => "String", - arrayType => ["Array(", this.crystalType(arrayType.items, withIssues), ")"], - classType => this.nameForNamedType(classType), - mapType => ["Hash(String, ", this.crystalType(mapType.values, withIssues), ")"], - _enumType => "String", - unionType => { + (_anyType) => + maybeAnnotated( + withIssues, + anyTypeIssueAnnotation, + "JSON::Any?", + ), + (_nullType) => + maybeAnnotated(withIssues, nullTypeIssueAnnotation, "Nil"), + (_boolType) => "Bool", + (_integerType) => "Int32", + (_doubleType) => "Float64", + (_stringType) => "String", + (arrayType) => [ + "Array(", + this.crystalType(arrayType.items, withIssues), + ")", + ], + (classType) => this.nameForNamedType(classType), + (mapType) => [ + "Hash(String, ", + this.crystalType(mapType.values, withIssues), + ")", + ], + (_enumType) => "String", + (unionType) => { const nullable = nullableFromUnion(unionType); - if (nullable !== null) return this.nullableCrystalType(nullable, withIssues); + if (nullable !== null) + return this.nullableCrystalType(nullable, withIssues); const [hasNull] = removeNullFromUnion(unionType); const name = this.nameForNamedType(unionType); return hasNull !== null ? ([name, "?"] as Sourcelike) : name; - } + }, ); } @@ -105,9 +151,16 @@ export class CrystalRenderer extends ConvenienceRenderer { const structBody = (): void => this.forEachClassProperty(c, "none", (name, jsonName, prop) => { this.ensureBlankLine(); - this.emitDescription(this.descriptionForClassProperty(c, jsonName)); + this.emitDescription( + this.descriptionForClassProperty(c, jsonName), + ); this.emitRenameAttribute(name, jsonName); - this.emitLine("property ", name, " : ", this.crystalType(prop.type, true)); + this.emitLine( + "property ", + name, + " : ", + this.crystalType(prop.type, true), + ); }); this.emitBlock(["class ", className], structBody); @@ -140,7 +193,7 @@ export class CrystalRenderer extends ConvenienceRenderer { const [, nonNulls] = removeNullFromUnion(u); - let types: Sourcelike[][] = []; + const types: Sourcelike[][] = []; this.forEachUnionMember(u, nonNulls, "none", null, (_name, t) => { const crystalType = this.breakCycle(t, true); types.push([crystalType]); @@ -150,7 +203,9 @@ 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(" | "), ]); } @@ -173,10 +228,15 @@ export class CrystalRenderer extends ConvenienceRenderer { 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)); - this.forEachUnion("leading-and-interposing", (u, name) => this.emitUnion(u, name)); + this.forEachObject( + "leading-and-interposing", + (c: ClassType, name: Name) => this.emitStructDefinition(c, name), + ); + this.forEachUnion("leading-and-interposing", (u, name) => + this.emitUnion(u, name), + ); } } diff --git a/packages/quicktype-core/src/language/Crystal/constants.ts b/packages/quicktype-core/src/language/Crystal/constants.ts index 9f9f99c5..06ff747c 100644 --- a/packages/quicktype-core/src/language/Crystal/constants.ts +++ b/packages/quicktype-core/src/language/Crystal/constants.ts @@ -134,5 +134,5 @@ export const keywords = [ "when", "while", "with", - "yield" + "yield", ] as const; diff --git a/packages/quicktype-core/src/language/Crystal/language.ts b/packages/quicktype-core/src/language/Crystal/language.ts index db61e48b..85772f2e 100644 --- a/packages/quicktype-core/src/language/Crystal/language.ts +++ b/packages/quicktype-core/src/language/Crystal/language.ts @@ -1,4 +1,4 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { TargetLanguage } from "../../TargetLanguage"; import { CrystalRenderer } from "./CrystalRenderer"; @@ -6,10 +6,12 @@ import { CrystalRenderer } from "./CrystalRenderer"; export const crystalLanguageConfig = { displayName: "Crystal", names: ["crystal", "cr", "crystallang"], - extension: "cr" + extension: "cr", } as const; -export class CrystalTargetLanguage extends TargetLanguage { +export class CrystalTargetLanguage extends TargetLanguage< + typeof crystalLanguageConfig +> { public constructor() { super(crystalLanguageConfig); } diff --git a/packages/quicktype-core/src/language/Crystal/utils.ts b/packages/quicktype-core/src/language/Crystal/utils.ts index a4d95da5..1a0c9a27 100644 --- a/packages/quicktype-core/src/language/Crystal/utils.ts +++ b/packages/quicktype-core/src/language/Crystal/utils.ts @@ -11,7 +11,7 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap + utf32ConcatMap, } from "../../support/Strings"; function isAsciiLetterOrUnderscoreOrDigit(codePoint: number): boolean { @@ -45,14 +45,19 @@ function crystalStyle(original: string, isSnakeCase: boolean): string { wordStyle, wordStyle, isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore + 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)); +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) { @@ -62,4 +67,6 @@ function standardUnicodeCrystalEscape(codePoint: number): string { } } -export const crystalStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeCrystalEscape)); +export const crystalStringEscape = utf32ConcatMap( + escapeNonPrintableMapper(isPrintable, standardUnicodeCrystalEscape), +); diff --git a/packages/quicktype-core/src/language/Dart/DartRenderer.ts b/packages/quicktype-core/src/language/Dart/DartRenderer.ts index 9eb8be9d..e81524ba 100644 --- a/packages/quicktype-core/src/language/Dart/DartRenderer.ts +++ b/packages/quicktype-core/src/language/Dart/DartRenderer.ts @@ -1,18 +1,39 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +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 { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated, modifySource } from "../../Source"; 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"; -import { directlyReachableSingleNamedType, matchType, nullableFromUnion } from "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import { + type ClassProperty, + type ClassType, + EnumType, + type Type, + type UnionType, +} from "../../Type"; +import { + directlyReachableSingleNamedType, + matchType, + nullableFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type dartOptions } from "./language"; -import { enumCaseNamingFunction, propertyNamingFunction, stringEscape, typeNamingFunction } from "./utils"; +import type { dartOptions } from "./language"; +import { + enumCaseNamingFunction, + propertyNamingFunction, + stringEscape, + typeNamingFunction, +} from "./utils"; interface TopLevelDependents { decoder: Name; @@ -20,7 +41,10 @@ interface TopLevelDependents { } export class DartRenderer extends ConvenienceRenderer { - private readonly _gettersAndSettersForPropertyName = new Map(); + private readonly _gettersAndSettersForPropertyName = new Map< + Name, + [Name, Name] + >(); private _needEnumValues = false; @@ -35,7 +59,7 @@ export class DartRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -44,7 +68,10 @@ export class DartRenderer extends ConvenienceRenderer { return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties( + _c: ClassType, + _className: Name, + ): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -83,16 +110,19 @@ export class DartRenderer extends ConvenienceRenderer { 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]; @@ -103,10 +133,18 @@ export class DartRenderer extends ConvenienceRenderer { _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)}`); + 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]; } @@ -115,16 +153,29 @@ export class DartRenderer extends ConvenienceRenderer { className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { - const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, 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`); + const enumValue = new DependencyName( + propertyNamingFunction, + name.order, + (lookup) => `${lookup(name)}_values`, + ); this._enumValues.set(t, enumValue); return [enumValue]; } @@ -141,7 +192,13 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine("//"); this.forEachTopLevel("none", (_t, name) => { const { decoder } = defined(this._topLevelDependents.get(name)); - this.emitLine("// final ", modifySource(decapitalize, name), " = ", decoder, "(jsonString);"); + this.emitLine( + "// final ", + modifySource(decapitalize, name), + " = ", + decoder, + "(jsonString);", + ); }); } @@ -151,7 +208,9 @@ export class DartRenderer extends ConvenienceRenderer { } if (this._options.useFreezed) { - this.emitLine("import 'package:freezed_annotation/freezed_annotation.dart';"); + this.emitLine( + "import 'package:freezed_annotation/freezed_annotation.dart';", + ); } if (this._options.useHive) { @@ -160,17 +219,25 @@ export class DartRenderer extends ConvenienceRenderer { 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';"); + this.emitLine( + "import 'package:json_annotation/json_annotation.dart';", + ); } this.emitLine("import 'dart:convert';"); - if (this._options.useFreezed || this._options.useHive || this._options.useJsonAnnotation) { + if ( + this._options.useFreezed || + this._options.useHive || + this._options.useJsonAnnotation + ) { this.ensureBlankLine(); const optionNameIsEmpty = this._options.partName.length === 0; // 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';"); @@ -192,23 +259,43 @@ export class DartRenderer extends ConvenienceRenderer { 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"), - _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, "dynamic"), - _boolType => withNullable("bool"), - _integerType => withNullable("int"), - _doubleType => withNullable("double"), - _stringType => withNullable("String"), - arrayType => withNullable(["List<", this.dartType(arrayType.items, withIssues), ">"]), - classType => withNullable(this.nameForNamedType(classType)), - mapType => withNullable(["Map"]), - enumType => withNullable(this.nameForNamedType(enumType)), - unionType => { + (_anyType) => + maybeAnnotated(withIssues, anyTypeIssueAnnotation, "dynamic"), + (_nullType) => + maybeAnnotated(withIssues, nullTypeIssueAnnotation, "dynamic"), + (_boolType) => withNullable("bool"), + (_integerType) => withNullable("int"), + (_doubleType) => withNullable("double"), + (_stringType) => withNullable("String"), + (arrayType) => + withNullable([ + "List<", + this.dartType(arrayType.items, withIssues), + ">", + ]), + (classType) => withNullable(this.nameForNamedType(classType)), + (mapType) => + withNullable([ + "Map", + ]), + (enumType) => withNullable(this.nameForNamedType(enumType)), + (unionType) => { const maybeNullable = nullableFromUnion(unionType); if (maybeNullable === null) { return "dynamic"; @@ -216,7 +303,7 @@ export class DartRenderer extends ConvenienceRenderer { return withNullable(this.dartType(maybeNullable, withIssues)); }, - transformedStringType => { + (transformedStringType) => { switch (transformedStringType.kind) { case "date-time": case "date": @@ -224,28 +311,88 @@ export class DartRenderer extends ConvenienceRenderer { default: return withNullable("String"); } - } + }, ); } - 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, "))"]; + 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, "))"]; + return [ + "List<", + itemType, + ">.from(", + list, + ".map((x) => ", + mapper, + "))", + ]; } - 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, "))"]; + 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, "))"]; + return [ + "Map.from(", + map, + ").map((k, v) => MapEntry(k, ", + valueMapper, + "))", + ]; } - protected mapClass(isNullable: boolean, classType: ClassType, dynamic: Sourcelike): Sourcelike { - if (this._options.nullSafety && isNullable && !this._options.requiredProperties) { + protected mapClass( + isNullable: boolean, + classType: ClassType, + dynamic: Sourcelike, + ): Sourcelike { + if ( + this._options.nullSafety && + isNullable && + !this._options.requiredProperties + ) { return [ dynamic, " == null ? null : ", @@ -254,11 +401,18 @@ export class DartRenderer extends ConvenienceRenderer { this.fromJson, "(", dynamic, - ")" + ")", ]; } - return [this.nameForNamedType(classType), ".", this.fromJson, "(", dynamic, ")"]; + return [ + this.nameForNamedType(classType), + ".", + this.fromJson, + "(", + dynamic, + ")", + ]; } // FIXME: refactor this @@ -266,47 +420,71 @@ export class DartRenderer extends ConvenienceRenderer { // 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 { + protected fromDynamicExpression( + isNullable = false, + t: Type, + ...dynamic: Sourcelike[] + ): Sourcelike { return matchType( t, - _anyType => dynamic, - _nullType => dynamic, // FIXME: check null - _boolType => dynamic, - _integerType => dynamic, - _doubleType => [dynamic, this._options.nullSafety ? "?.toDouble()" : ".toDouble()"], - _stringType => dynamic, - arrayType => + (_anyType) => dynamic, + (_nullType) => dynamic, // FIXME: check null + (_boolType) => dynamic, + (_integerType) => dynamic, + (_doubleType) => [ + dynamic, + this._options.nullSafety ? "?.toDouble()" : ".toDouble()", + ], + (_stringType) => dynamic, + (arrayType) => this.mapList( 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 => + (classType) => + this.mapClass( + isNullable || classType.isNullable, + classType, + dynamic, + ), + (mapType) => this.mapMap( 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 => { + (enumType) => { return [ defined(this._enumValues.get(enumType)), ".map[", dynamic, - this._options.nullSafety ? "]!" : "]" + this._options.nullSafety ? "]!" : "]", ]; }, - unionType => { + (unionType) => { const maybeNullable = nullableFromUnion(unionType); if (maybeNullable === null) { return dynamic; } - return this.fromDynamicExpression(unionType.isNullable, maybeNullable, dynamic); + return this.fromDynamicExpression( + unionType.isNullable, + maybeNullable, + dynamic, + ); }, - transformedStringType => { + (transformedStringType) => { switch (transformedStringType.kind) { case "date-time": case "date": @@ -315,14 +493,20 @@ export class DartRenderer extends ConvenienceRenderer { !this._options.requiredProperties && this._options.nullSafety ) { - return [dynamic, " == null ? null : ", "DateTime.parse(", dynamic, ")"]; + return [ + dynamic, + " == null ? null : ", + "DateTime.parse(", + dynamic, + ")", + ]; } return ["DateTime.parse(", dynamic, ")"]; default: return dynamic; } - } + }, ); } @@ -331,23 +515,31 @@ export class DartRenderer extends ConvenienceRenderer { // 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 { + protected toDynamicExpression( + isNullable = false, + t: Type, + ...dynamic: Sourcelike[] + ): Sourcelike { return matchType( t, - _anyType => dynamic, - _nullType => dynamic, - _boolType => dynamic, - _integerType => dynamic, - _doubleType => dynamic, - _stringType => dynamic, - arrayType => + (_anyType) => dynamic, + (_nullType) => dynamic, + (_boolType) => dynamic, + (_integerType) => dynamic, + (_doubleType) => dynamic, + (_stringType) => dynamic, + (arrayType) => this.mapList( arrayType.isNullable || isNullable, "dynamic", dynamic, - this.toDynamicExpression(arrayType.items.isNullable, arrayType.items, "x") + this.toDynamicExpression( + arrayType.items.isNullable, + arrayType.items, + "x", + ), ), - _classType => { + (_classType) => { if ( this._options.nullSafety && (_classType.isNullable || isNullable) && @@ -358,25 +550,38 @@ export class DartRenderer extends ConvenienceRenderer { return [dynamic, ".", this.toJson, "()"]; }, - mapType => + (mapType) => this.mapMap( 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, "]"]; + (enumType) => { + return [ + defined(this._enumValues.get(enumType)), + ".reverse[", + dynamic, + "]", + ]; }, - unionType => { + (unionType) => { const maybeNullable = nullableFromUnion(unionType); if (maybeNullable === null) { return dynamic; } - return this.toDynamicExpression(unionType.isNullable, maybeNullable, dynamic); + return this.toDynamicExpression( + unionType.isNullable, + maybeNullable, + dynamic, + ); }, - transformedStringType => { + (transformedStringType) => { switch (transformedStringType.kind) { case "date-time": if ( @@ -402,7 +607,7 @@ export class DartRenderer extends ConvenienceRenderer { dynamic, "!.month.toString().padLeft(2, '0')}-${", dynamic, - "!.day.toString().padLeft(2, '0')}\"" + "!.day.toString().padLeft(2, '0')}\"", ]; } @@ -414,12 +619,12 @@ export class DartRenderer extends ConvenienceRenderer { dynamic, ".month.toString().padLeft(2, '0')}-${", dynamic, - ".day.toString().padLeft(2, '0')}\"" + ".day.toString().padLeft(2, '0')}\"", ]; default: return dynamic; } - } + }, ); } @@ -433,7 +638,8 @@ export class DartRenderer extends ConvenienceRenderer { 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, ","); }); }); @@ -458,7 +664,13 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine(`@JsonKey(name: "${jsonName}")`); } - this.emitLine(this._options.finalProperties ? "final " : "", this.dartType(p.type, true), " ", name, ";"); + this.emitLine( + this._options.finalProperties ? "final " : "", + this.dartType(p.type, true), + " ", + name, + ";", + ); }); } @@ -467,7 +679,12 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine(className, " copyWith({"); this.indent(() => { this.forEachClassProperty(c, "none", (name, _, _p) => { - this.emitLine(this.dartType(_p.type, true, true), " ", name, ","); + this.emitLine( + this.dartType(_p.type, true, true), + " ", + name, + ",", + ); }); }); this.emitLine("}) => "); @@ -493,22 +710,32 @@ export class DartRenderer extends ConvenienceRenderer { className, ".", this.fromJson, - "(json.decode(str));" + "(json.decode(str));", ); this.ensureBlankLine(); this.emitLine( "String ", - this._options.methodNamesWithMap ? "toJson() => " : "toRawJson() => ", + this._options.methodNamesWithMap + ? "toJson() => " + : "toRawJson() => ", "json.encode(", this.toJson, - "());" + "());", ); } private _emitMapEncoderDecoder(c: ClassType, className: Name): void { this.ensureBlankLine(); - this.emitLine("factory ", className, ".", this.fromJson, "(Map json) => ", className, "("); + this.emitLine( + "factory ", + className, + ".", + this.fromJson, + "(Map json) => ", + className, + "(", + ); this.indent(() => { this.forEachClassProperty(c, "none", (name, jsonName, property) => { this.emitLine( @@ -519,9 +746,9 @@ export class DartRenderer extends ConvenienceRenderer { property.type, 'json["', stringEscape(jsonName), - '"]' + '"]', ), - "," + ",", ); }); }); @@ -536,8 +763,12 @@ export class DartRenderer extends ConvenienceRenderer { '"', stringEscape(jsonName), '": ', - this.toDynamicExpression(property.type.isNullable, property.type, name), - "," + this.toDynamicExpression( + property.type.isNullable, + property.type, + name, + ), + ",", ); }); }); @@ -578,7 +809,7 @@ export class DartRenderer extends ConvenienceRenderer { ".fromJson(Map json) => ", "_$", className, - "FromJson(json);" + "FromJson(json);", ); this.ensureBlankLine(); @@ -587,7 +818,7 @@ export class DartRenderer extends ConvenienceRenderer { "Map toJson() => ", "_$", className, - "ToJson(this);" + "ToJson(this);", ); } else { if (this._options.justTypes) return; @@ -607,26 +838,45 @@ export class DartRenderer extends ConvenienceRenderer { this.emitLine("@freezed"); this.emitBlock(["class ", className, " with _$", className], () => { if (c.getProperties().size === 0) { - this.emitLine("const factory ", className, "() = _", className, ";"); + this.emitLine( + "const factory ", + className, + "() = _", + className, + ";", + ); } else { this.emitLine("const factory ", className, "({"); this.indent(() => { - this.forEachClassProperty(c, "none", (name, jsonName, prop) => { - const description = this.descriptionForClassProperty(c, jsonName); - if (description !== undefined) { - this.emitDescription(description); - } + this.forEachClassProperty( + c, + "none", + (name, jsonName, prop) => { + const description = + this.descriptionForClassProperty(c, jsonName); + if (description !== undefined) { + this.emitDescription(description); + } - const required = - this._options.requiredProperties || - (this._options.nullSafety && (!prop.type.isNullable || !prop.isOptional)); - if (this._options.useJsonAnnotation) { - this.classPropertyCounter++; - this.emitLine(`@JsonKey(name: "${jsonName}")`); - } + const required = + this._options.requiredProperties || + (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, ","); - }); + this.emitLine( + required ? "required " : "", + this.dartType(prop.type, true), + " ", + name, + ",", + ); + }, + ); }); this.emitLine("}) = _", className, ";"); } @@ -641,7 +891,7 @@ export class DartRenderer extends ConvenienceRenderer { ".fromJson(Map json) => ", "_$", className, - "FromJson(json);" + "FromJson(json);", ); }); } @@ -664,11 +914,23 @@ export class DartRenderer extends ConvenienceRenderer { if (this._options.justTypes) return; this.ensureBlankLine(); - this.emitLine("final ", defined(this._enumValues.get(e)), " = EnumValues({"); + this.emitLine( + "final ", + defined(this._enumValues.get(e)), + " = EnumValues({", + ); 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("});"); @@ -693,7 +955,9 @@ export class DartRenderer extends ConvenienceRenderer { private _emitTopLvlEncoderDecoder(): void { this.forEachTopLevel("leading-and-interposing", (t, name) => { - const { encoder, decoder } = defined(this._topLevelDependents.get(name)); + const { encoder, decoder } = defined( + this._topLevelDependents.get(name), + ); this.emitLine( this.dartType(t), @@ -701,7 +965,7 @@ export class DartRenderer extends ConvenienceRenderer { decoder, "(String str) => ", this.fromDynamicExpression(t.isNullable, t, "json.decode(str)"), - ";" + ";", ); this.ensureBlankLine(); @@ -713,7 +977,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)"], () => { @@ -732,11 +996,13 @@ export class DartRenderer extends ConvenienceRenderer { this.forEachNamedType( "leading-and-interposing", (c: ClassType, n: Name) => - this._options.useFreezed ? this.emitFreezedClassDefinition(c, n) : this.emitClassDefinition(c, n), + this._options.useFreezed + ? this.emitFreezedClassDefinition(c, n) + : this.emitClassDefinition(c, n), (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/Dart/constants.ts b/packages/quicktype-core/src/language/Dart/constants.ts index 1251a6d8..6aef1d3c 100644 --- a/packages/quicktype-core/src/language/Dart/constants.ts +++ b/packages/quicktype-core/src/language/Dart/constants.ts @@ -67,5 +67,5 @@ export const keywords = [ "fromJson", "toJson", "fromMap", - "toMap" + "toMap", ] as const; diff --git a/packages/quicktype-core/src/language/Dart/language.ts b/packages/quicktype-core/src/language/Dart/language.ts index 5687c893..cc80a8b6 100644 --- a/packages/quicktype-core/src/language/Dart/language.ts +++ b/packages/quicktype-core/src/language/Dart/language.ts @@ -1,39 +1,84 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; -import { type StringTypeMapping } from "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } 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), + 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" + "secondary", + ), + useHive: new BooleanOption( + "use-hive", + "Generate annotations for Hive type adapters", + 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" + "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 const dartLanguageConfig = { displayName: "Dart", names: ["dart"], extension: "dart" } as const; +export const dartLanguageConfig = { + displayName: "Dart", + names: ["dart"], + extension: "dart", +} as const; -export class DartTargetLanguage extends TargetLanguage { +export class DartTargetLanguage extends TargetLanguage< + typeof dartLanguageConfig +> { public constructor() { super(dartLanguageConfig); } @@ -47,13 +92,17 @@ export class DartTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); mapping.set("date", "date"); mapping.set("date-time", "date-time"); return mapping; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): DartRenderer { + protected makeRenderer( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index 2fb4a783..0a2825b4 100644 --- a/packages/quicktype-core/src/language/Dart/utils.ts +++ b/packages/quicktype-core/src/language/Dart/utils.ts @@ -12,16 +12,25 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../../support/Strings"; -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)); +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) + escapeNonPrintableMapper( + (cp) => isPrintable(cp) && cp !== 0x24, + standardUnicodeHexEscape, + ), ); function isStartCharacter(codePoint: number): boolean { @@ -30,7 +39,10 @@ function isStartCharacter(codePoint: number): boolean { } function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); + return ( + isStartCharacter(codePoint) || + (isAscii(codePoint) && isDigit(codePoint)) + ); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); @@ -39,14 +51,20 @@ 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 -export function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, original: string): string { +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; + const restWordStyle = upperUnderscore + ? allUpperWordStyle + : firstUpperWordStyle; return combineWords( words, legalizeName, @@ -55,6 +73,6 @@ export function dartNameStyle(startWithUpper: boolean, upperUnderscore: boolean, firstWordStyle, restWordStyle, upperUnderscore ? "_" : "", - isStartCharacter + isStartCharacter, ); } diff --git a/packages/quicktype-core/src/language/Elixir/ElixirRenderer.ts b/packages/quicktype-core/src/language/Elixir/ElixirRenderer.ts index 6edb5593..c35ea00b 100644 --- a/packages/quicktype-core/src/language/Elixir/ElixirRenderer.ts +++ b/packages/quicktype-core/src/language/Elixir/ElixirRenderer.ts @@ -1,28 +1,39 @@ -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +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 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 "../../Type/TypeUtils"; import { forbiddenModuleNames, reservedWords } from "./constants"; -import { type elixirOptions } from "./language"; +import type { elixirOptions } from "./language"; import { capitalizeFirstLetter, escapeDoubleQuotes, escapeNewLines, memberNameStyle, simpleNameStyle, - stringEscape + stringEscape, } from "./utils"; export class ElixirRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -40,15 +51,24 @@ export class ElixirRenderer extends ConvenienceRenderer { } protected forbiddenNamesForGlobalNamespace(): string[] { - return [...forbiddenModuleNames, ...reservedWords.map(word => capitalizeFirstLetter(word))]; + return [ + ...forbiddenModuleNames, + ...reservedWords.map((word) => capitalizeFirstLetter(word)), + ]; } - protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { - return { names: reservedWords as unknown as string[], includeGlobalForbidden: true }; + protected forbiddenForObjectProperties( + _c: ClassType, + _classNamed: Name, + ): ForbiddenWordsInfo { + return { + names: reservedWords as unknown as string[], + includeGlobalForbidden: true, + }; } protected makeNamedTypeNamer(): Namer { - return new Namer("types", n => simpleNameStyle(n, true), []); + return new Namer("types", (n) => simpleNameStyle(n, true), []); } protected namerForObjectProperty(): Namer { @@ -60,57 +80,100 @@ export class ElixirRenderer extends ConvenienceRenderer { } protected makeEnumCaseNamer(): Namer { - return new Namer("enum-cases", n => simpleNameStyle(n, true), []); + return new Namer("enum-cases", (n) => simpleNameStyle(n, true), []); } private nameForNamedTypeWithNamespace(t: Type): Sourcelike { if (this._options.namespace) { return [this._options.namespace, ".", this.nameForNamedType(t)]; - } else { - return [this.nameForNamedType(t)]; } + + return [this.nameForNamedType(t)]; } private nameWithNamespace(n: Name): Sourcelike { if (this._options.namespace) { return [this._options.namespace, ".", n]; - } else { - return [n]; } + + return [n]; } private elixirType(t: Type, isOptional = false): Sourcelike { const optional = isOptional ? " | nil" : ""; return matchType( t, - _anyType => ["any()", optional], - _nullType => ["nil"], - _boolType => ["boolean()", optional], - _integerType => ["integer()", optional], - _doubleType => ["float()", optional], - _stringType => ["String.t()", optional], - arrayType => ["[", this.elixirType(arrayType.items), "]", optional], - classType => [this.nameForNamedTypeWithNamespace(classType), ".t()", optional], - mapType => ["%{String.t() => ", this.elixirType(mapType.values), "}", optional], - enumType => [this.nameForNamedTypeWithNamespace(enumType), ".t()", optional], - unionType => { - const children = [...unionType.getChildren()].map(ut => this.elixirType(ut)); + (_anyType) => ["any()", optional], + (_nullType) => ["nil"], + (_boolType) => ["boolean()", optional], + (_integerType) => ["integer()", optional], + (_doubleType) => ["float()", optional], + (_stringType) => ["String.t()", optional], + (arrayType) => [ + "[", + this.elixirType(arrayType.items), + "]", + optional, + ], + (classType) => [ + this.nameForNamedTypeWithNamespace(classType), + ".t()", + optional, + ], + (mapType) => [ + "%{String.t() => ", + this.elixirType(mapType.values), + "}", + optional, + ], + (enumType) => [ + this.nameForNamedTypeWithNamespace(enumType), + ".t()", + optional, + ], + (unionType) => { + const children = [...unionType.getChildren()].map((ut) => + this.elixirType(ut), + ); return [ - children.flatMap((element, index) => (index === children.length - 1 ? element : [element, " | "])), - optional + children.flatMap((element, index) => + index === children.length - 1 + ? element + : [element, " | "], + ), + optional, ]; - } + }, ); } - private patternMatchClauseDecode(t: Type, attributeName: Sourcelike, suffix = ""): Sourcelike { + private patternMatchClauseDecode( + t: Type, + attributeName: Sourcelike, + suffix = "", + ): Sourcelike { return matchType( t, - _anyType => [], - _nullType => ["def decode_", attributeName, suffix, "(value) when is_nil(value), do: value"], - _boolType => ["def decode_", attributeName, suffix, "(value) when is_boolean(value), do: value"], - _integerType => ["def decode_", attributeName, suffix, "(value) when is_integer(value), do: value"], - _doubleType => [ + (_anyType) => [], + (_nullType) => [ + "def decode_", + attributeName, + suffix, + "(value) when is_nil(value), do: value", + ], + (_boolType) => [ + "def decode_", + attributeName, + suffix, + "(value) when is_boolean(value), do: value", + ], + (_integerType) => [ + "def decode_", + attributeName, + suffix, + "(value) when is_integer(value), do: value", + ], + (_doubleType) => [ "def decode_", attributeName, suffix, @@ -118,17 +181,35 @@ export class ElixirRenderer extends ConvenienceRenderer { "def decode_", attributeName, suffix, - "(value) when is_integer(value), do: value" + "(value) when is_integer(value), do: value", ], - _stringType => ["def decode_", attributeName, suffix, "(value) when is_binary(value), do: value"], - _arrayType => ["def decode_", attributeName, suffix, "(value) when is_list(value), do: value"], - classType => { + (_stringType) => [ + "def decode_", + attributeName, + suffix, + "(value) when is_binary(value), do: value", + ], + (_arrayType) => [ + "def decode_", + attributeName, + suffix, + "(value) when is_list(value), do: value", + ], + (classType) => { const requiredAttributeArgs: Sourcelike[] = []; - this.forEachClassProperty(classType, "none", (_name, jsonName, p) => { - if (!p.isOptional) { - requiredAttributeArgs.push(['"', jsonName, '" => _,']); - } - }); + this.forEachClassProperty( + classType, + "none", + (_name, jsonName, p) => { + if (!p.isOptional) { + requiredAttributeArgs.push([ + '"', + jsonName, + '" => _,', + ]); + } + }, + ); return [ "def decode_", attributeName, @@ -137,31 +218,55 @@ export class ElixirRenderer extends ConvenienceRenderer { requiredAttributeArgs, "} = value), do: ", this.nameForNamedTypeWithNamespace(classType), - ".from_map(value)" + ".from_map(value)", ]; }, - _mapType => ["def decode_", attributeName, suffix, "(value) when is_map(value), do: value"], - enumType => [ + (_mapType) => [ + "def decode_", + attributeName, + suffix, + "(value) when is_map(value), do: value", + ], + (enumType) => [ "def decode_", attributeName, suffix, "(value) when is_binary(value)", ", do: ", this.nameForNamedTypeWithNamespace(enumType), - ".decode(value)" + ".decode(value)", ], - _unionType => [] + (_unionType) => [], ); } - private patternMatchClauseEncode(t: Type, attributeName: Sourcelike, suffix = ""): Sourcelike { + private patternMatchClauseEncode( + t: Type, + attributeName: Sourcelike, + suffix = "", + ): Sourcelike { return matchType( t, - _anyType => [], - _nullType => ["def encode_", attributeName, suffix, "(value) when is_nil(value), do: value"], - _boolType => ["def encode_", attributeName, suffix, "(value) when is_boolean(value), do: value"], - _integerType => ["def encode_", attributeName, suffix, "(value) when is_integer(value), do: value"], - _doubleType => [ + (_anyType) => [], + (_nullType) => [ + "def encode_", + attributeName, + suffix, + "(value) when is_nil(value), do: value", + ], + (_boolType) => [ + "def encode_", + attributeName, + suffix, + "(value) when is_boolean(value), do: value", + ], + (_integerType) => [ + "def encode_", + attributeName, + suffix, + "(value) when is_integer(value), do: value", + ], + (_doubleType) => [ "def encode_", attributeName, suffix, @@ -169,17 +274,35 @@ export class ElixirRenderer extends ConvenienceRenderer { "def encode_", attributeName, suffix, - "(value) when is_integer(value), do: value" + "(value) when is_integer(value), do: value", ], - _stringType => ["def encode_", attributeName, suffix, "(value) when is_binary(value), do: value"], - _arrayType => ["def encode_", attributeName, suffix, "(value) when is_list(value), do: value"], - classType => { + (_stringType) => [ + "def encode_", + attributeName, + suffix, + "(value) when is_binary(value), do: value", + ], + (_arrayType) => [ + "def encode_", + attributeName, + suffix, + "(value) when is_list(value), do: value", + ], + (classType) => { const requiredAttributeArgs: Sourcelike[] = []; - this.forEachClassProperty(classType, "none", (_name, jsonName, p) => { - if (!p.isOptional) { - requiredAttributeArgs.push(['"', jsonName, '" => _,']); - } - }); + this.forEachClassProperty( + classType, + "none", + (_name, jsonName, p) => { + if (!p.isOptional) { + requiredAttributeArgs.push([ + '"', + jsonName, + '" => _,', + ]); + } + }, + ); return [ "def encode_", attributeName, @@ -188,46 +311,58 @@ export class ElixirRenderer extends ConvenienceRenderer { this.nameForNamedTypeWithNamespace(classType), "{} = value), do: ", this.nameForNamedTypeWithNamespace(classType), - ".to_map(value)" + ".to_map(value)", ]; }, - _mapType => ["def encode_", attributeName, suffix, "(value) when is_map(value), do: value"], - enumType => [ + (_mapType) => [ + "def encode_", + attributeName, + suffix, + "(value) when is_map(value), do: value", + ], + (enumType) => [ "def encode_", attributeName, suffix, "(value) when is_atom(value)", ", do: ", this.nameForNamedTypeWithNamespace(enumType), - ".encode(value)" + ".encode(value)", ], - _unionType => [] + (_unionType) => [], ); } private sortAndFilterPatternMatchTypes(types: Type[]): Type[] { return types - .filter(type => !(type instanceof UnionType)) + .filter((type) => !(type instanceof UnionType)) .sort((a, b) => { if (a instanceof ClassType && !(b instanceof ClassType)) { return -1; - } else if (b instanceof ClassType && !(a instanceof ClassType)) { - return 1; - } else if (a.kind === "bool" && b.kind !== "bool") { - return -1; - } else if (b.kind === "bool" && a.kind !== "bool") { - return 1; - } else if (a instanceof EnumType && !(b instanceof EnumType)) { - return -1; - } else if (b instanceof EnumType && !(a instanceof EnumType)) { - return 1; - } else if (a.isPrimitive() && !b.isPrimitive()) { - return -1; - } else if (b.isPrimitive() && !a.isPrimitive()) { - return 1; - } else { - return 0; } + if (b instanceof ClassType && !(a instanceof ClassType)) { + return 1; + } + if (a.kind === "bool" && b.kind !== "bool") { + return -1; + } + if (b.kind === "bool" && a.kind !== "bool") { + return 1; + } + if (a instanceof EnumType && !(b instanceof EnumType)) { + return -1; + } + if (b instanceof EnumType && !(a instanceof EnumType)) { + return 1; + } + if (a.isPrimitive() && !b.isPrimitive()) { + return -1; + } + if (b.isPrimitive() && !a.isPrimitive()) { + return 1; + } + + return 0; }); } @@ -236,7 +371,7 @@ export class ElixirRenderer extends ConvenienceRenderer { name: Sourcelike, parentName: Sourcelike, suffix = "", - optional = false + optional = false, ): void { this.ensureBlankLine(); @@ -245,16 +380,23 @@ export class ElixirRenderer extends ConvenienceRenderer { return; } - if (typesToMatch.find(type => type.kind === "double")) { - typesToMatch = typesToMatch.filter(type => type.kind !== "integer"); + if (typesToMatch.find((type) => type.kind === "double")) { + typesToMatch = typesToMatch.filter( + (type) => type.kind !== "integer", + ); } - typesToMatch.forEach(type => { + typesToMatch.forEach((type) => { this.emitLine(this.patternMatchClauseDecode(type, name, suffix)); }); - if (optional && !typesToMatch.find(type => type.kind === "null")) { - this.emitLine("def decode_", name, suffix, "(value) when is_nil(value), do: value"); + if (optional && !typesToMatch.find((type) => type.kind === "null")) { + this.emitLine( + "def decode_", + name, + suffix, + "(value) when is_nil(value), do: value", + ); } this.emitLine( @@ -265,17 +407,22 @@ export class ElixirRenderer extends ConvenienceRenderer { parentName, ".", name, - '"}' + '"}', ); this.ensureBlankLine(); - typesToMatch.forEach(type => { + typesToMatch.forEach((type) => { this.emitLine(this.patternMatchClauseEncode(type, name, suffix)); }); - if (optional && !typesToMatch.find(type => type.kind === "null")) { - this.emitLine("def encode_", name, suffix, "(value) when is_nil(value), do: value"); + if (optional && !typesToMatch.find((type) => type.kind === "null")) { + this.emitLine( + "def encode_", + name, + suffix, + "(value) when is_nil(value), do: value", + ); } this.emitLine( @@ -286,13 +433,18 @@ export class ElixirRenderer extends ConvenienceRenderer { parentName, ".", name, - '"}' + '"}', ); this.ensureBlankLine(); } - private nameOfTransformFunction(t: Type, name: Name | Sourcelike, encode = false, prefix = ""): Sourcelike { + private nameOfTransformFunction( + t: Type, + name: Name | Sourcelike, + encode = false, + prefix = "", + ): Sourcelike { let mode = "decode"; if (encode) { mode = "encode"; @@ -300,112 +452,151 @@ export class ElixirRenderer extends ConvenienceRenderer { return matchType( t, - _anyType => [], - _nullType => [], - _boolType => [], - _integerType => [], - _doubleType => [], - _stringType => [], - _arrayType => [], - classType => [this.nameForNamedTypeWithNamespace(classType), `.${encode ? "to" : "from"}_map`], - _mapType => [], - enumType => { - return [this.nameForNamedTypeWithNamespace(enumType), `.${mode}`]; + (_anyType) => [], + (_nullType) => [], + (_boolType) => [], + (_integerType) => [], + (_doubleType) => [], + (_stringType) => [], + (_arrayType) => [], + (classType) => [ + this.nameForNamedTypeWithNamespace(classType), + `.${encode ? "to" : "from"}_map`, + ], + (_mapType) => [], + (enumType) => { + return [ + this.nameForNamedTypeWithNamespace(enumType), + `.${mode}`, + ]; }, - _unionType => { + (_unionType) => { return [`${mode}_`, name, prefix]; - } + }, ); } - private fromDynamic(t: Type, jsonName: string, name: Name, optional = false): Sourcelike { + private fromDynamic( + t: Type, + jsonName: string, + name: Name, + optional = false, + ): Sourcelike { const primitive = ['m["', jsonName, '"]']; return matchType( t, - _anyType => primitive, - _nullType => primitive, - _boolType => primitive, - _integerType => primitive, - _doubleType => primitive, - _stringType => primitive, - arrayType => { + (_anyType) => primitive, + (_nullType) => primitive, + (_boolType) => primitive, + (_integerType) => primitive, + (_doubleType) => primitive, + (_stringType) => primitive, + (arrayType) => { const arrayElement = arrayType.items; if (arrayElement instanceof ArrayType) { return primitive; - } else if (arrayElement.isPrimitive()) { - return primitive; - } else if (arrayElement instanceof MapType) { - return primitive; - } else { - if (optional) { - return [ - "m", - '["', - jsonName, - '"] && Enum.map(m["', - jsonName, - '"], &', - this.nameOfTransformFunction(arrayElement, name, false, "_element"), - "/1)" - ]; - } else { - return [ - 'Enum.map(m["', - jsonName, - '"], &', - this.nameOfTransformFunction(arrayElement, name, false, "_element"), - "/1)" - ]; - } } + if (arrayElement.isPrimitive()) { + return primitive; + } + if (arrayElement instanceof MapType) { + return primitive; + } + + if (optional) { + return [ + "m", + '["', + jsonName, + '"] && Enum.map(m["', + jsonName, + '"], &', + this.nameOfTransformFunction( + arrayElement, + name, + false, + "_element", + ), + "/1)", + ]; + } + + return [ + 'Enum.map(m["', + jsonName, + '"], &', + this.nameOfTransformFunction( + arrayElement, + name, + false, + "_element", + ), + "/1)", + ]; }, - classType => [ + (classType) => [ optional ? [primitive, " && "] : "", this.nameForNamedTypeWithNamespace(classType), ".from_map(", primitive, - ")" + ")", ], - mapType => { + (mapType) => { const mapValueTypes = [...mapType.values.getChildren()]; - const mapValueTypesNotPrimitive = mapValueTypes.filter(type => !(type instanceof PrimitiveType)); + const mapValueTypesNotPrimitive = mapValueTypes.filter( + (type) => !(type instanceof PrimitiveType), + ); if (mapValueTypesNotPrimitive.length === 0) { - return [primitive]; - } else { - if (mapType.values.kind === "union") { - return [ - 'm["', - jsonName, - '"]\n|> Map.new(fn {key, value} -> {key, ', - this.nameOfTransformFunction(mapType.values, jsonName, false), - "_value(value)} end)" - ]; - } else if (mapType.values instanceof EnumType || mapType.values instanceof ClassType) { - return [ - 'm["', - jsonName, - '"]\n|> Map.new(fn {key, value} -> {key, ', - this.nameOfTransformFunction(mapType.values, jsonName, false), - "(value)} end)" - ]; - } - return [primitive]; } + + if (mapType.values.kind === "union") { + return [ + 'm["', + jsonName, + '"]\n|> Map.new(fn {key, value} -> {key, ', + this.nameOfTransformFunction( + mapType.values, + jsonName, + false, + ), + "_value(value)} end)", + ]; + } + if ( + mapType.values instanceof EnumType || + mapType.values instanceof ClassType + ) { + return [ + 'm["', + jsonName, + '"]\n|> Map.new(fn {key, value} -> {key, ', + this.nameOfTransformFunction( + mapType.values, + jsonName, + false, + ), + "(value)} end)", + ]; + } + + return [primitive]; }, - enumType => { + (enumType) => { return [ optional ? [primitive, " && "] : "", this.nameOfTransformFunction(enumType, name), "(", primitive, - ")" + ")", ]; }, - unionType => { + (unionType) => { const unionTypes = [...unionType.getChildren()]; - const unionPrimitiveTypes = unionTypes.filter(type => type.isPrimitive()); + const unionPrimitiveTypes = unionTypes.filter((type) => + type.isPrimitive(), + ); if (unionTypes.length === unionPrimitiveTypes.length) { return ['m["', jsonName, '"]']; } @@ -422,11 +613,19 @@ export class ElixirRenderer extends ConvenienceRenderer { return this.fromDynamic(nullable, jsonName, name, true); } - return ['m["', jsonName, '"] && decode_', name, '(m["', jsonName, '"])']; + return [ + 'm["', + jsonName, + '"] && decode_', + name, + '(m["', + jsonName, + '"])', + ]; } return ["decode_", name, '(m["', jsonName, '"])']; - } + }, ); } @@ -434,13 +633,13 @@ export class ElixirRenderer extends ConvenienceRenderer { const expression = ["struct.", e]; return matchType( t, - _anyType => expression, - _nullType => expression, - _boolType => expression, - _integerType => expression, - _doubleType => expression, - _stringType => expression, - arrayType => { + (_anyType) => expression, + (_nullType) => expression, + (_boolType) => expression, + (_integerType) => expression, + (_doubleType) => expression, + (_stringType) => expression, + (arrayType) => { const arrayElement = arrayType.items; if (arrayElement instanceof ArrayType) { return expression; @@ -448,83 +647,102 @@ export class ElixirRenderer extends ConvenienceRenderer { if (arrayElement.isPrimitive()) { return expression; - } else if (arrayElement instanceof MapType) { - return expression; - } else { - if (arrayElement.kind === "array") { - return expression; - } else { - if (optional) { - return [ - "struct.", - e, - " && Enum.map(struct.", - e, - ", &", - this.nameOfTransformFunction(arrayElement, e, true, "_element"), - "/1)" - ]; - } else { - return [ - "struct.", - e, - " && Enum.map(struct.", - e, - ", &", - this.nameOfTransformFunction(arrayElement, e, true, "_element"), - "/1)" - ]; - } - } } + if (arrayElement instanceof MapType) { + return expression; + } + + if (arrayElement.kind === "array") { + return expression; + } + + if (optional) { + return [ + "struct.", + e, + " && Enum.map(struct.", + e, + ", &", + this.nameOfTransformFunction( + arrayElement, + e, + true, + "_element", + ), + "/1)", + ]; + } + + return [ + "struct.", + e, + " && Enum.map(struct.", + e, + ", &", + this.nameOfTransformFunction( + arrayElement, + e, + true, + "_element", + ), + "/1)", + ]; }, - classType => [ + (classType) => [ optional ? ["struct.", e, " && "] : "", this.nameForNamedTypeWithNamespace(classType), ".to_map(", "struct.", e, - ")" + ")", ], - mapType => { + (mapType) => { const mapValueTypes = [...mapType.values.getChildren()]; - const mapValueTypesNotPrimitive = mapValueTypes.filter(type => !(type instanceof PrimitiveType)); + const mapValueTypesNotPrimitive = mapValueTypes.filter( + (type) => !(type instanceof PrimitiveType), + ); if (mapValueTypesNotPrimitive.length === 0) { - return [expression]; - } else { - if (mapType.values.kind === "union") { - return [ - "struct.", - e, - "\n|> Map.new(fn {key, value} -> {key, ", - this.nameOfTransformFunction(mapType.values, e, true), - "_value(value)} end)" - ]; - } else if (mapType.values instanceof EnumType || mapType.values instanceof ClassType) { - return [ - "struct.", - e, - "\n|> Map.new(fn {key, value} -> {key, ", - this.nameOfTransformFunction(mapType.values, e, true), - "(value)} end)" - ]; - } - return [expression]; } + + if (mapType.values.kind === "union") { + return [ + "struct.", + e, + "\n|> Map.new(fn {key, value} -> {key, ", + this.nameOfTransformFunction(mapType.values, e, true), + "_value(value)} end)", + ]; + } + if ( + mapType.values instanceof EnumType || + mapType.values instanceof ClassType + ) { + return [ + "struct.", + e, + "\n|> Map.new(fn {key, value} -> {key, ", + this.nameOfTransformFunction(mapType.values, e, true), + "(value)} end)", + ]; + } + + return [expression]; }, - enumType => { + (enumType) => { return [ optional ? ["struct.", e, " && "] : "", this.nameForNamedTypeWithNamespace(enumType), ".encode(struct.", e, - ")" + ")", ]; }, - unionType => { + (unionType) => { const unionTypes = [...unionType.getChildren()]; - const unionPrimitiveTypes = unionTypes.filter(type => type.isPrimitive()); + const unionPrimitiveTypes = unionTypes.filter((type) => + type.isPrimitive(), + ); if (unionTypes.length === unionPrimitiveTypes.length) { return ["struct.", e]; } @@ -544,7 +762,7 @@ export class ElixirRenderer extends ConvenienceRenderer { } return ["encode_", e, "(struct.", e, ")"]; - } + }, ); } @@ -558,167 +776,241 @@ export class ElixirRenderer extends ConvenienceRenderer { this.emitCommentLines(lines, { firstLineStart: '@moduledoc """\n', lineStart: "", - afterComment: '"""' + afterComment: '"""', }); } protected emitModule(c: ClassType, moduleName: Name): void { - this.emitBlock(["defmodule ", this.nameWithNamespace(moduleName), " do"], () => { - const structDescription = this.descriptionForType(c) ?? []; - const attributeDescriptions: Sourcelike[][] = []; - this.forEachClassProperty(c, "none", (name, jsonName, _p) => { - const attributeDescription = this.descriptionForClassProperty(c, jsonName); - if (attributeDescription) { - attributeDescriptions.push(["- `:", name, "` - ", attributeDescription]); - } - }); - if (structDescription.length || attributeDescriptions.length) { - this.emitDescription([...structDescription, ...attributeDescriptions]); - this.ensureBlankLine(); - } - - const requiredAttributes: Sourcelike[] = []; - this.forEachClassProperty(c, "none", (name, _jsonName, p) => { - if (!p.isOptional) { - if (requiredAttributes.length === 0) { - requiredAttributes.push([":", name]); - } else { - requiredAttributes.push([", :", name]); - } - } - }); - if (requiredAttributes.length) { - this.emitLine(["@enforce_keys [", requiredAttributes, "]"]); - } - - const attributeNames: Sourcelike[] = []; - this.forEachClassProperty(c, "none", (name, _jsonName, _p) => { - if (attributeNames.length === 0) { - attributeNames.push([":", name]); - } else { - attributeNames.push([", :", name]); - } - }); - - this.emitLine(["defstruct [", attributeNames, "]"]); - this.ensureBlankLine(); - - const typeDefinitionTable: Sourcelike[][] = [[["@type "], ["t :: %__MODULE__{"]]]; - let count = c.getProperties().size; - this.forEachClassProperty(c, "none", (name, _jsonName, p) => { - const last = --count === 0; - const attributeRow = [ - [], - [" ", name, ": ", this.elixirType(p.type), p.isOptional ? " | nil" : "", last ? "" : ","] - ]; - typeDefinitionTable.push(attributeRow); - }); - typeDefinitionTable.push([[], ["}"]]); - this.emitTable(typeDefinitionTable); - if (this._options.justTypes) { - return; - } - - this.forEachClassProperty(c, "none", (name, _jsonName, p) => { - if (p.type.kind === "union") { - const unionTypes = [...p.type.getChildren()]; - const unionPrimitiveTypes = unionTypes.filter(type => type.isPrimitive()); - if (unionTypes.length === unionPrimitiveTypes.length) { - return; - } - - const unionTypesNonNull = unionTypes.filter(type => type.kind !== "null"); - if (unionTypesNonNull.length === 1) { - let suffix = ""; - let itemTypes: Type[] = []; - if (unionTypesNonNull[0] instanceof ArrayType) { - suffix = "_element"; - itemTypes = [...unionTypesNonNull[0].getChildren()]; - } else if (unionTypesNonNull[0] instanceof MapType) { - suffix = "_value"; - itemTypes = [...unionTypesNonNull[0].getChildren()]; - } - - if (itemTypes.length === 1 && itemTypes[0] instanceof UnionType) { - itemTypes = [...itemTypes[0].getChildren()]; - } - - this.emitPatternMatches( - itemTypes, + this.emitBlock( + ["defmodule ", this.nameWithNamespace(moduleName), " do"], + () => { + const structDescription = this.descriptionForType(c) ?? []; + const attributeDescriptions: Sourcelike[][] = []; + this.forEachClassProperty(c, "none", (name, jsonName, _p) => { + const attributeDescription = + this.descriptionForClassProperty(c, jsonName); + if (attributeDescription) { + attributeDescriptions.push([ + "- `:", name, - this.nameForNamedTypeWithNamespace(c), - suffix, - p.isOptional - ); - } else { - this.emitPatternMatches( - unionTypes, - name, - this.nameForNamedTypeWithNamespace(c), - "", - p.isOptional - ); + "` - ", + attributeDescription, + ]); } - } else if (p.type.kind === "array") { - const arrayType = p.type as ArrayType; - if (arrayType.items instanceof UnionType) { - const unionType = arrayType.items; - const typesInUnion = [...unionType.getChildren()]; - - this.emitPatternMatches(typesInUnion, name, this.nameForNamedTypeWithNamespace(c), "_element"); - } - } else if (p.type.kind === "map") { - const mapType = p.type as MapType; - if (mapType.values instanceof UnionType) { - const unionType = mapType.values; - const typesInUnion = [...unionType.getChildren()]; - - this.emitPatternMatches(typesInUnion, name, this.nameForNamedTypeWithNamespace(c), "_value"); - } - } - }); - let propCount = 0; - this.forEachClassProperty(c, "none", (_name, _jsonName, _p) => { - propCount++; - }); - const isEmpty = propCount ? false : true; - this.ensureBlankLine(); - this.emitBlock([`def from_map(${isEmpty ? "_" : ""}m) do`], () => { - this.emitLine("%", this.nameWithNamespace(moduleName), "{"); - this.indent(() => { - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - jsonName = escapeDoubleQuotes(jsonName); - jsonName = escapeNewLines(jsonName); - const expression = this.fromDynamic(p.type, jsonName, name, p.isOptional); - this.emitLine(name, ": ", expression, ","); - }); }); - this.emitLine("}"); - }); - this.ensureBlankLine(); - this.emitBlock("def from_json(json) do", () => { - this.emitMultiline(`json + if (structDescription.length || attributeDescriptions.length) { + this.emitDescription([ + ...structDescription, + ...attributeDescriptions, + ]); + this.ensureBlankLine(); + } + + const requiredAttributes: Sourcelike[] = []; + this.forEachClassProperty(c, "none", (name, _jsonName, p) => { + if (!p.isOptional) { + if (requiredAttributes.length === 0) { + requiredAttributes.push([":", name]); + } else { + requiredAttributes.push([", :", name]); + } + } + }); + if (requiredAttributes.length) { + this.emitLine(["@enforce_keys [", requiredAttributes, "]"]); + } + + const attributeNames: Sourcelike[] = []; + this.forEachClassProperty(c, "none", (name, _jsonName, _p) => { + if (attributeNames.length === 0) { + attributeNames.push([":", name]); + } else { + attributeNames.push([", :", name]); + } + }); + + this.emitLine(["defstruct [", attributeNames, "]"]); + this.ensureBlankLine(); + + const typeDefinitionTable: Sourcelike[][] = [ + [["@type "], ["t :: %__MODULE__{"]], + ]; + let count = c.getProperties().size; + this.forEachClassProperty(c, "none", (name, _jsonName, p) => { + const last = --count === 0; + const attributeRow = [ + [], + [ + " ", + name, + ": ", + this.elixirType(p.type), + p.isOptional ? " | nil" : "", + last ? "" : ",", + ], + ]; + typeDefinitionTable.push(attributeRow); + }); + typeDefinitionTable.push([[], ["}"]]); + this.emitTable(typeDefinitionTable); + if (this._options.justTypes) { + return; + } + + this.forEachClassProperty(c, "none", (name, _jsonName, p) => { + if (p.type.kind === "union") { + const unionTypes = [...p.type.getChildren()]; + const unionPrimitiveTypes = unionTypes.filter((type) => + type.isPrimitive(), + ); + if (unionTypes.length === unionPrimitiveTypes.length) { + return; + } + + const unionTypesNonNull = unionTypes.filter( + (type) => type.kind !== "null", + ); + if (unionTypesNonNull.length === 1) { + let suffix = ""; + let itemTypes: Type[] = []; + if (unionTypesNonNull[0] instanceof ArrayType) { + suffix = "_element"; + itemTypes = [ + ...unionTypesNonNull[0].getChildren(), + ]; + } else if ( + unionTypesNonNull[0] instanceof MapType + ) { + suffix = "_value"; + itemTypes = [ + ...unionTypesNonNull[0].getChildren(), + ]; + } + + if ( + itemTypes.length === 1 && + itemTypes[0] instanceof UnionType + ) { + itemTypes = [...itemTypes[0].getChildren()]; + } + + this.emitPatternMatches( + itemTypes, + name, + this.nameForNamedTypeWithNamespace(c), + suffix, + p.isOptional, + ); + } else { + this.emitPatternMatches( + unionTypes, + name, + this.nameForNamedTypeWithNamespace(c), + "", + p.isOptional, + ); + } + } else if (p.type.kind === "array") { + const arrayType = p.type as ArrayType; + if (arrayType.items instanceof UnionType) { + const unionType = arrayType.items; + const typesInUnion = [...unionType.getChildren()]; + + this.emitPatternMatches( + typesInUnion, + name, + this.nameForNamedTypeWithNamespace(c), + "_element", + ); + } + } else if (p.type.kind === "map") { + const mapType = p.type as MapType; + if (mapType.values instanceof UnionType) { + const unionType = mapType.values; + const typesInUnion = [...unionType.getChildren()]; + + this.emitPatternMatches( + typesInUnion, + name, + this.nameForNamedTypeWithNamespace(c), + "_value", + ); + } + } + }); + let propCount = 0; + this.forEachClassProperty(c, "none", (_name, _jsonName, _p) => { + propCount++; + }); + const isEmpty = propCount ? false : true; + this.ensureBlankLine(); + this.emitBlock( + [`def from_map(${isEmpty ? "_" : ""}m) do`], + () => { + this.emitLine( + "%", + this.nameWithNamespace(moduleName), + "{", + ); + this.indent(() => { + this.forEachClassProperty( + c, + "none", + (name, jsonName, p) => { + jsonName = escapeDoubleQuotes(jsonName); + jsonName = escapeNewLines(jsonName); + const expression = this.fromDynamic( + p.type, + jsonName, + name, + p.isOptional, + ); + this.emitLine(name, ": ", expression, ","); + }, + ); + }); + this.emitLine("}"); + }, + ); + this.ensureBlankLine(); + this.emitBlock("def from_json(json) do", () => { + this.emitMultiline(`json |> Jason.decode!() |> from_map()`); - }); - this.ensureBlankLine(); - this.emitBlock([`def to_map(${isEmpty ? "_" : ""}struct) do`], () => { - this.emitLine("%{"); - this.indent(() => { - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - const expression = this.toDynamic(p.type, name, p.isOptional); - this.emitLine([[`"${stringEscape(jsonName)}"`], [" => ", expression, ","]]); - }); }); - this.emitLine("}"); - }); - this.ensureBlankLine(); - this.emitBlock("def to_json(struct) do", () => { - this.emitMultiline(`struct + this.ensureBlankLine(); + this.emitBlock( + [`def to_map(${isEmpty ? "_" : ""}struct) do`], + () => { + this.emitLine("%{"); + this.indent(() => { + this.forEachClassProperty( + c, + "none", + (name, jsonName, p) => { + const expression = this.toDynamic( + p.type, + name, + p.isOptional, + ); + this.emitLine([ + [`"${stringEscape(jsonName)}"`], + [" => ", expression, ","], + ]); + }, + ); + }); + this.emitLine("}"); + }, + ); + this.ensureBlankLine(); + this.emitBlock("def to_json(struct) do", () => { + this.emitMultiline(`struct |> to_map() |> Jason.encode!()`); - }); - }); + }); + }, + ); } private isValidAtom(str: string): boolean { @@ -742,7 +1034,11 @@ export class ElixirRenderer extends ConvenienceRenderer { for (let i = 1; i < str.length; i++) { const char = str[i]; - if (!isLetterOrDigit(char) && char !== "@" && !(i === str.length - 1 && (char === "!" || char === "?"))) { + if ( + !isLetterOrDigit(char) && + char !== "@" && + !(i === str.length - 1 && (char === "!" || char === "?")) + ) { return false; } } @@ -751,24 +1047,26 @@ export class ElixirRenderer extends ConvenienceRenderer { } protected emitEnum(e: EnumType, enumName: Name): void { - this.emitBlock(["defmodule ", this.nameWithNamespace(enumName), " do"], () => { - this.emitDescription(this.descriptionForType(e)); - this.emitLine("@valid_enum_members ["); - this.indent(() => { - this.forEachEnumCase(e, "none", (_name, json) => { - if (this.isValidAtom(json)) { - this.emitLine(":", json, ","); - } else { - this.emitLine(":", `"${json}"`, ","); - } + this.emitBlock( + ["defmodule ", this.nameWithNamespace(enumName), " do"], + () => { + this.emitDescription(this.descriptionForType(e)); + this.emitLine("@valid_enum_members ["); + this.indent(() => { + this.forEachEnumCase(e, "none", (_name, json) => { + if (this.isValidAtom(json)) { + this.emitLine(":", json, ","); + } else { + this.emitLine(":", `"${json}"`, ","); + } + }); }); - }); - this.emitLine("]"); + this.emitLine("]"); - this.ensureBlankLine(); + this.ensureBlankLine(); - this.emitMultiline(`def valid_atom?(value), do: value in @valid_enum_members + this.emitMultiline(`def valid_atom?(value), do: value in @valid_enum_members def valid_atom_string?(value) do try do @@ -806,7 +1104,8 @@ def to_json(data) do |> encode() |> Jason.encode!() end`); - }); + }, + ); } protected emitUnion(_u: UnionType, _unionName: Name): void { @@ -822,8 +1121,16 @@ end`); # Add Jason to your mix.exs`); this.forEachTopLevel("none", (_topLevel, name) => { this.emitLine("#"); - this.emitLine("# Decode a JSON string: ", this.nameWithNamespace(name), ".from_json(data)"); - this.emitLine("# Encode into a JSON string: ", this.nameWithNamespace(name), ".to_json(struct)"); + this.emitLine( + "# Decode a JSON string: ", + this.nameWithNamespace(name), + ".from_json(data)", + ); + this.emitLine( + "# Encode into a JSON string: ", + this.nameWithNamespace(name), + ".to_json(struct)", + ); }); } @@ -833,7 +1140,7 @@ end`); "leading-and-interposing", (c: ClassType, n: Name) => this.emitModule(c, n), (e, n) => this.emitEnum(e, n), - (u, n) => this.emitUnion(u, n) + (u, n) => this.emitUnion(u, n), ); if (!this._options.justTypes) { @@ -842,59 +1149,74 @@ end`); (topLevel, name) => { const isTopLevelArray = "array" === topLevel.kind; - this.emitBlock(["defmodule ", this.nameWithNamespace(name), " do"], () => { - const description = this.descriptionForType(topLevel) ?? []; - if (description.length) { - this.emitDescription([...description]); - this.ensureBlankLine(); - } - - if (isTopLevelArray) { - const arrayElement = (topLevel as ArrayType).items; - - let isUnion = false; - - if (arrayElement instanceof UnionType) { - this.emitPatternMatches([...arrayElement.getChildren()], "element", name); - isUnion = true; + this.emitBlock( + ["defmodule ", this.nameWithNamespace(name), " do"], + () => { + const description = + this.descriptionForType(topLevel) ?? []; + if (description.length) { + this.emitDescription([...description]); + this.ensureBlankLine(); } - this.emitBlock("def from_json(json) do", () => { - this.emitLine("json"); - this.emitLine("|> Jason.decode!()"); - this.emitLine( - "|> Enum.map(&", - isUnion - ? ["decode_element/1)"] - : [this.nameWithNamespace(name), "Element.from_map/1)"] - ); - }); + if (isTopLevelArray) { + const arrayElement = (topLevel as ArrayType) + .items; - this.ensureBlankLine(); + let isUnion = false; - this.emitBlock("def to_json(list) do", () => { - this.emitLine( - "Enum.map(list, &", - isUnion - ? ["encode_element/1)"] - : [this.nameWithNamespace(name), "Element.to_map/1)"] - ); - this.emitLine("|> Jason.encode!()"); - }); - } else { - this.emitBlock("def from_json(json) do", () => { - this.emitLine("Jason.decode!(json)"); - }); + if (arrayElement instanceof UnionType) { + this.emitPatternMatches( + [...arrayElement.getChildren()], + "element", + name, + ); + isUnion = true; + } - this.ensureBlankLine(); + this.emitBlock("def from_json(json) do", () => { + this.emitLine("json"); + this.emitLine("|> Jason.decode!()"); + this.emitLine( + "|> Enum.map(&", + isUnion + ? ["decode_element/1)"] + : [ + this.nameWithNamespace(name), + "Element.from_map/1)", + ], + ); + }); - this.emitBlock("def to_json(data) do", () => { - this.emitLine("Jason.encode!(data)"); - }); - } - }); + this.ensureBlankLine(); + + this.emitBlock("def to_json(list) do", () => { + this.emitLine( + "Enum.map(list, &", + isUnion + ? ["encode_element/1)"] + : [ + this.nameWithNamespace(name), + "Element.to_map/1)", + ], + ); + this.emitLine("|> Jason.encode!()"); + }); + } else { + this.emitBlock("def from_json(json) do", () => { + this.emitLine("Jason.decode!(json)"); + }); + + this.ensureBlankLine(); + + this.emitBlock("def to_json(data) do", () => { + this.emitLine("Jason.encode!(data)"); + }); + } + }, + ); }, - t => this.namedTypeToNameForTopLevel(t) === undefined + (t) => this.namedTypeToNameForTopLevel(t) === undefined, ); } } diff --git a/packages/quicktype-core/src/language/Elixir/constants.ts b/packages/quicktype-core/src/language/Elixir/constants.ts index 89866c9f..6216baa7 100644 --- a/packages/quicktype-core/src/language/Elixir/constants.ts +++ b/packages/quicktype-core/src/language/Elixir/constants.ts @@ -74,7 +74,7 @@ export const forbiddenModuleNames = [ "UndefinedFunctionError", "UnicodeConversionError", "Version", - "WithClauseError" + "WithClauseError", ] as const; export const reservedWords = [ @@ -97,5 +97,5 @@ export const reservedWords = [ "catch", "rescue", "after", - "else" + "else", ] as const; diff --git a/packages/quicktype-core/src/language/Elixir/language.ts b/packages/quicktype-core/src/language/Elixir/language.ts index 37b15d4c..01783d1c 100644 --- a/packages/quicktype-core/src/language/Elixir/language.ts +++ b/packages/quicktype-core/src/language/Elixir/language.ts @@ -1,22 +1,33 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } 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", "") + namespace: new StringOption( + "namespace", + "Specify a module namespace", + "NAME", + "", + ), }; export const elixirLanguageConfig = { displayName: "Elixir", names: ["elixir"], - extension: "ex" + extension: "ex", } as const; -export class ElixirTargetLanguage extends TargetLanguage { +export class ElixirTargetLanguage extends TargetLanguage< + typeof elixirLanguageConfig +> { public constructor() { super(elixirLanguageConfig); } @@ -33,7 +44,14 @@ export class ElixirTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index 4e81841f..2e2439e3 100644 --- a/packages/quicktype-core/src/language/Elixir/utils.ts +++ b/packages/quicktype-core/src/language/Elixir/utils.ts @@ -11,7 +11,7 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap + utf32ConcatMap, } from "../../support/Strings"; function unicodeEscape(codePoint: number): string { @@ -22,7 +22,9 @@ export function capitalizeFirstLetter(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } -export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); +export const stringEscape = utf32ConcatMap( + escapeNonPrintableMapper(isPrintable, unicodeEscape), +); export function escapeDoubleQuotes(str: string): string { return str.replace(/"/g, '\\"'); @@ -36,7 +38,10 @@ const isStartCharacter = isLetterOrUnderscore; function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); + return ( + ["Nd", "Pc", "Mn", "Mc"].includes(category) || + isStartCharacter(utf16Unit) + ); } const legalizeName = legalizeCharacters(isPartCharacter); @@ -55,7 +60,7 @@ export function simpleNameStyle(original: string, uppercase: boolean): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -69,6 +74,6 @@ export function memberNameStyle(original: string): string { allLowerWordStyle, allLowerWordStyle, "_", - isStartCharacter + isStartCharacter, ); } diff --git a/packages/quicktype-core/src/language/Elm/ElmRenderer.ts b/packages/quicktype-core/src/language/Elm/ElmRenderer.ts index fcfd06b1..b11daadf 100644 --- a/packages/quicktype-core/src/language/Elm/ElmRenderer.ts +++ b/packages/quicktype-core/src/language/Elm/ElmRenderer.ts @@ -1,20 +1,43 @@ import { arrayIntercalate, mapContains } from "collection-utils"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +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 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 type { TargetLanguage } from "../../TargetLanguage"; +import type { + ClassProperty, + ClassType, + EnumType, + Type, + UnionType, +} from "../../Type"; import { matchType, nullableFromUnion } from "../../Type/TypeUtils"; import { forbiddenNames } from "./constants"; -import { type elmOptions } from "./language"; -import { lowerNamingFunction, requiredOrOptional, upperNamingFunction } from "./utils"; +import type { elmOptions } from "./language"; +import { + lowerNamingFunction, + requiredOrOptional, + upperNamingFunction, +} from "./utils"; interface TopLevelDependent { decoder?: Name; @@ -34,7 +57,7 @@ export class ElmRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -43,15 +66,22 @@ export class ElmRenderer extends ConvenienceRenderer { 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)); + decoder = new DependencyName( + lowerNamingFunction, + topLevelName.order, + (lookup) => lookup(topLevelName), + ); } this._topLevelDependents.set(topLevelName, { encoder, decoder }); @@ -66,9 +96,20 @@ export class ElmRenderer extends ConvenienceRenderer { return upperNamingFunction; } - 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)); + 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]; } @@ -77,7 +118,10 @@ export class ElmRenderer extends ConvenienceRenderer { return lowerNamingFunction; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties( + _c: ClassType, + _className: Name, + ): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -101,9 +145,14 @@ export class ElmRenderer extends ConvenienceRenderer { u: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { - const fieldName = super.proposeUnionMemberName(u, unionName, fieldType, lookup); + const fieldName = super.proposeUnionMemberName( + u, + unionName, + fieldType, + lookup, + ); return `${fieldName}_in_${lookup(unionName)}`; } @@ -113,9 +162,15 @@ export class ElmRenderer extends ConvenienceRenderer { protected emitDescriptionBlock(lines: Sourcelike[]): void { if (lines.length === 1) { - this.emitComments([{ customLines: lines, lineStart: "{-| ", lineEnd: " -}" }]); + this.emitComments([ + { customLines: lines, lineStart: "{-| ", lineEnd: " -}" }, + ]); } else { - this.emitCommentLines(lines, { firstLineStart: "{-| ", lineStart: "", afterComment: "-}" }); + this.emitCommentLines(lines, { + firstLineStart: "{-| ", + lineStart: "", + afterComment: "-}", + }); } } @@ -126,17 +181,28 @@ export class ElmRenderer extends ConvenienceRenderer { private elmType(t: Type, noOptional = false): MultiWord { return matchType( t, - _anyType => singleWord(annotated(anyTypeIssueAnnotation, "Jdec.Value")), - _nullType => singleWord(annotated(nullTypeIssueAnnotation, "()")), - _boolType => singleWord("Bool"), - _integerType => singleWord("Int"), - _doubleType => singleWord("Float"), - _stringType => singleWord("String"), - arrayType => multiWord(" ", this.arrayType, parenIfNeeded(this.elmType(arrayType.items))), - classType => singleWord(this.nameForNamedType(classType)), - mapType => multiWord(" ", "Dict String", parenIfNeeded(this.elmType(mapType.values))), - enumType => singleWord(this.nameForNamedType(enumType)), - unionType => { + (_anyType) => + singleWord(annotated(anyTypeIssueAnnotation, "Jdec.Value")), + (_nullType) => singleWord(annotated(nullTypeIssueAnnotation, "()")), + (_boolType) => singleWord("Bool"), + (_integerType) => singleWord("Int"), + (_doubleType) => singleWord("Float"), + (_stringType) => singleWord("String"), + (arrayType) => + multiWord( + " ", + this.arrayType, + parenIfNeeded(this.elmType(arrayType.items)), + ), + (classType) => singleWord(this.nameForNamedType(classType)), + (mapType) => + multiWord( + " ", + "Dict String", + parenIfNeeded(this.elmType(mapType.values)), + ), + (enumType) => singleWord(this.nameForNamedType(enumType)), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { const nullableType = this.elmType(nullable); @@ -145,16 +211,20 @@ export class ElmRenderer extends ConvenienceRenderer { } return singleWord(this.nameForNamedType(unionType)); - } + }, ); } private elmProperty(p: ClassProperty): Sourcelike { if (p.isOptional) { - return multiWord(" ", "Maybe", parenIfNeeded(this.elmType(p.type, true))).source; - } else { - return this.elmType(p.type).source; + return multiWord( + " ", + "Maybe", + parenIfNeeded(this.elmType(p.type, true)), + ).source; } + + return this.elmType(p.type).source; } private decoderNameForNamedType(t: Type): Name { @@ -165,40 +235,53 @@ export class ElmRenderer extends ConvenienceRenderer { private decoderNameForType(t: Type, noOptional = false): MultiWord { return matchType( t, - _anyType => singleWord("Jdec.value"), - _nullType => multiWord(" ", "Jdec.null", "()"), - _boolType => singleWord("Jdec.bool"), - _integerType => singleWord("Jdec.int"), - _doubleType => singleWord("Jdec.float"), - _stringType => singleWord("Jdec.string"), - arrayType => + (_anyType) => singleWord("Jdec.value"), + (_nullType) => multiWord(" ", "Jdec.null", "()"), + (_boolType) => singleWord("Jdec.bool"), + (_integerType) => singleWord("Jdec.int"), + (_doubleType) => singleWord("Jdec.float"), + (_stringType) => singleWord("Jdec.string"), + (arrayType) => 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))), - enumType => singleWord(this.decoderNameForNamedType(enumType)), - unionType => { + (classType) => singleWord(this.decoderNameForNamedType(classType)), + (mapType) => + multiWord( + " ", + "Jdec.dict", + parenIfNeeded(this.decoderNameForType(mapType.values)), + ), + (enumType) => singleWord(this.decoderNameForNamedType(enumType)), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { const nullableDecoder = this.decoderNameForType(nullable); if (noOptional) return nullableDecoder; - return multiWord(" ", "Jdec.nullable", parenIfNeeded(nullableDecoder)); + return multiWord( + " ", + "Jdec.nullable", + parenIfNeeded(nullableDecoder), + ); } return singleWord(this.decoderNameForNamedType(unionType)); - } + }, ); } private decoderNameForProperty(p: ClassProperty): MultiWord { if (p.isOptional) { - return multiWord(" ", "Jdec.nullable", parenIfNeeded(this.decoderNameForType(p.type, true))); - } else { - return this.decoderNameForType(p.type); + return multiWord( + " ", + "Jdec.nullable", + parenIfNeeded(this.decoderNameForType(p.type, true)), + ); } + + return this.decoderNameForType(p.type); } private encoderNameForNamedType(t: Type): Name { @@ -209,50 +292,71 @@ export class ElmRenderer extends ConvenienceRenderer { private encoderNameForType(t: Type, noOptional = false): MultiWord { return matchType( t, - _anyType => singleWord("identity"), - _nullType => multiWord(" ", "always", "Jenc.null"), - _boolType => singleWord("Jenc.bool"), - _integerType => singleWord("Jenc.int"), - _doubleType => singleWord("Jenc.float"), - _stringType => singleWord("Jenc.string"), - arrayType => + (_anyType) => singleWord("identity"), + (_nullType) => multiWord(" ", "always", "Jenc.null"), + (_boolType) => singleWord("Jenc.bool"), + (_integerType) => singleWord("Jenc.int"), + (_doubleType) => singleWord("Jenc.float"), + (_stringType) => singleWord("Jenc.string"), + (arrayType) => 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))), - enumType => singleWord(this.encoderNameForNamedType(enumType)), - unionType => { + (classType) => singleWord(this.encoderNameForNamedType(classType)), + (mapType) => + multiWord( + " ", + "makeDictEncoder", + parenIfNeeded(this.encoderNameForType(mapType.values)), + ), + (enumType) => singleWord(this.encoderNameForNamedType(enumType)), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { const nullableEncoder = this.encoderNameForType(nullable); if (noOptional) return nullableEncoder; - return multiWord(" ", "makeNullableEncoder", parenIfNeeded(nullableEncoder)); + return multiWord( + " ", + "makeNullableEncoder", + parenIfNeeded(nullableEncoder), + ); } return singleWord(this.encoderNameForNamedType(unionType)); - } + }, ); } private encoderNameForProperty(p: ClassProperty): MultiWord { if (p.isOptional) { - return multiWord(" ", "makeNullableEncoder", parenIfNeeded(this.encoderNameForType(p.type, true))); - } else { - return this.encoderNameForType(p.type); + return multiWord( + " ", + "makeNullableEncoder", + parenIfNeeded(this.encoderNameForType(p.type, true)), + ); } + + return this.encoderNameForType(p.type); } private emitTopLevelDefinition(t: Type, topLevelName: Name): void { - this.emitLine("type alias ", topLevelName, " = ", this.elmType(t).source); + this.emitLine( + "type alias ", + topLevelName, + " = ", + this.elmType(t).source, + ); } private emitClassDefinition(c: ClassType, className: Name): void { let description = this.descriptionForType(c); this.forEachClassProperty(c, "none", (name, jsonName) => { - const propertyDescription = this.descriptionForClassProperty(c, jsonName); + const propertyDescription = this.descriptionForClassProperty( + c, + jsonName, + ); if (propertyDescription === undefined) return; if (description === undefined) { @@ -270,7 +374,13 @@ export class ElmRenderer extends ConvenienceRenderer { this.indent(() => { let onFirst = true; this.forEachClassProperty(c, "none", (name, _jsonName, p) => { - this.emitLine(onFirst ? "{" : ",", " ", name, " : ", this.elmProperty(p)); + this.emitLine( + onFirst ? "{" : ",", + " ", + name, + " : ", + this.elmProperty(p), + ); onFirst = false; }); if (onFirst) { @@ -286,7 +396,7 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine("type ", enumName); this.indent(() => { let onFirst = true; - this.forEachEnumCase(e, "none", name => { + this.forEachEnumCase(e, "none", (name) => { const equalsOrPipe = onFirst ? "=" : "|"; this.emitLine(equalsOrPipe, " ", name); onFirst = false; @@ -299,12 +409,18 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine("type ", unionName); this.indent(() => { let onFirst = true; - this.forEachUnionMember(u, null, "none", null, (constructor, t) => { + this.forEachUnionMember(u, null, "none", null, (name, t) => { const equalsOrPipe = onFirst ? "=" : "|"; if (t.kind === "null") { - this.emitLine(equalsOrPipe, " ", constructor); + this.emitLine(equalsOrPipe, " ", name); } else { - this.emitLine(equalsOrPipe, " ", constructor, " ", parenIfNeeded(this.elmType(t))); + this.emitLine( + equalsOrPipe, + " ", + name, + " ", + parenIfNeeded(this.elmType(t)), + ); } onFirst = false; @@ -313,15 +429,26 @@ export class ElmRenderer extends ConvenienceRenderer { } private emitTopLevelFunctions(t: Type, topLevelName: Name): void { - const { encoder, decoder } = defined(this._topLevelDependents.get(topLevelName)); + 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.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)"); + this.emitLine( + encoder, + " r = Jenc.encode 0 (", + this.encoderNameForType(t).source, + " r)", + ); } private emitClassFunctions(c: ClassType, className: Name): void { @@ -332,9 +459,19 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine("Jpipe.decode ", className); this.indent(() => { this.forEachClassProperty(c, "none", (_, jsonName, p) => { - const propDecoder = parenIfNeeded(this.decoderNameForProperty(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, + ); }); }); }); @@ -350,7 +487,16 @@ 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) { @@ -374,9 +520,18 @@ 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(")"); @@ -389,7 +544,12 @@ 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), + '"', + ); }); }); } @@ -399,9 +559,11 @@ export class ElmRenderer extends ConvenienceRenderer { function sortOrder(_: Name, t: Type): string { if (t.kind === "array") { return " array"; - } else if (t.kind === "double") { + } + if (t.kind === "double") { return " xdouble"; - } else if (t.isPrimitive()) { + } + if (t.isPrimitive()) { return " " + t.kind; } @@ -415,17 +577,31 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine("Jdec.oneOf"); this.indent(() => { let onFirst = true; - this.forEachUnionMember(u, null, "none", sortOrder, (constructor, t) => { - const bracketOrComma = onFirst ? "[" : ","; - if (t.kind === "null") { - this.emitLine(bracketOrComma, " Jdec.null ", constructor); - } else { - const decoder = parenIfNeeded(this.decoderNameForType(t)); - this.emitLine(bracketOrComma, " Jdec.map ", constructor, " ", decoder); - } + this.forEachUnionMember( + u, + null, + "none", + sortOrder, + (name, t) => { + const bracketOrComma = onFirst ? "[" : ","; + if (t.kind === "null") { + this.emitLine(bracketOrComma, " Jdec.null ", name); + } else { + const decoder = parenIfNeeded( + this.decoderNameForType(t), + ); + this.emitLine( + bracketOrComma, + " Jdec.map ", + name, + " ", + decoder, + ); + } - onFirst = false; - }); + onFirst = false; + }, + ); this.emitLine("]"); }); }); @@ -435,12 +611,12 @@ export class ElmRenderer extends ConvenienceRenderer { this.emitLine(encoderName, " : ", unionName, " -> Jenc.Value"); this.emitLine(encoderName, " x = case x of"); this.indent(() => { - this.forEachUnionMember(u, null, "none", sortOrder, (constructor, t) => { + this.forEachUnionMember(u, null, "none", sortOrder, (name, t) => { if (t.kind === "null") { - this.emitLine(constructor, " -> Jenc.null"); + this.emitLine(name, " -> Jenc.null"); } else { const encoder = this.encoderNameForType(t).source; - this.emitLine(constructor, " y -> ", encoder, " y"); + this.emitLine(name, " y -> ", encoder, " y"); } }); }); @@ -450,7 +626,9 @@ export class ElmRenderer extends ConvenienceRenderer { const exports: Sourcelike[] = []; const topLevelDecoders: Sourcelike[] = []; this.forEachTopLevel("none", (_, name) => { - let { encoder, decoder } = defined(this._topLevelDependents.get(name)); + let { encoder, decoder } = defined( + this._topLevelDependents.get(name), + ); if (decoder === undefined) { decoder = defined(this._namedTypeDependents.get(name)).decoder; } @@ -478,14 +656,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 @@ -493,7 +671,9 @@ export class ElmRenderer extends ConvenienceRenderer { this.forEachTopLevel("none", (_, name) => { let { decoder } = defined(this._topLevelDependents.get(name)); if (decoder === undefined) { - decoder = defined(this._namedTypeDependents.get(name)).decoder; + decoder = defined( + this._namedTypeDependents.get(name), + ).decoder; } this.emitLine("-- decodeString ", decoder, " myJsonString"); @@ -525,37 +705,58 @@ 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: Type, topLevelName: Name) => + this.emitTopLevelDefinition(t, topLevelName), + (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) + (c: ClassType, className: Name) => + this.emitClassDefinition(c, className), + (e: EnumType, enumName: Name) => + this.emitEnumDefinition(e, enumName), + (u: UnionType, unionName: Name) => + this.emitUnionDefinition(u, unionName), ); if (this._options.justTypes) return; this.ensureBlankLine(); this.emitLine("-- decoders and encoders"); - this.forEachTopLevel("leading-and-interposing", (t: Type, topLevelName: Name) => - this.emitTopLevelFunctions(t, topLevelName) + this.forEachTopLevel( + "leading-and-interposing", + (t: Type, topLevelName: Name) => + 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) + (c: ClassType, className: Name) => + this.emitClassFunctions(c, className), + (e: EnumType, enumName: Name) => + this.emitEnumFunctions(e, enumName), + (u: UnionType, unionName: Name) => + this.emitUnionFunctions(u, unionName), ); this.ensureBlankLine(); this.emitLine("--- encoder helpers"); this.ensureBlankLine(); - this.emitLine("make", this.arrayType, "Encoder : (a -> Jenc.Value) -> ", this.arrayType, " a -> Jenc.Value"); + this.emitLine( + "make", + this.arrayType, + "Encoder : (a -> Jenc.Value) -> ", + this.arrayType, + " a -> Jenc.Value", + ); this.emitLine("make", this.arrayType, "Encoder f arr ="); this.indent(() => { - this.emitLine("Jenc.", decapitalize(this.arrayType), " (", this.arrayType, ".map f arr)"); + this.emitLine( + "Jenc.", + decapitalize(this.arrayType), + " (", + this.arrayType, + ".map f arr)", + ); }); this.ensureBlankLine(); this.emitMultiline(`makeDictEncoder : (a -> Jenc.Value) -> Dict String a -> Jenc.Value diff --git a/packages/quicktype-core/src/language/Elm/constants.ts b/packages/quicktype-core/src/language/Elm/constants.ts index e7a331f8..5b3d1197 100644 --- a/packages/quicktype-core/src/language/Elm/constants.ts +++ b/packages/quicktype-core/src/language/Elm/constants.ts @@ -36,5 +36,5 @@ export const forbiddenNames = [ "True", "False", "String", - "Float" + "Float", ] as const; diff --git a/packages/quicktype-core/src/language/Elm/language.ts b/packages/quicktype-core/src/language/Elm/language.ts index d77d3b33..7fc11361 100644 --- a/packages/quicktype-core/src/language/Elm/language.ts +++ b/packages/quicktype-core/src/language/Elm/language.ts @@ -1,7 +1,12 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { ElmRenderer } from "./ElmRenderer"; @@ -12,21 +17,28 @@ export const elmOptions = { "Use Array or List", { array: false, - list: true + list: true, } as const, - "array" + "array", ), // 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 const elmLanguageConfig = { displayName: "Elm", names: ["elm"], - extension: "elm" + extension: "elm", } as const; -export class ElmTargetLanguage extends TargetLanguage { +export class ElmTargetLanguage extends TargetLanguage< + typeof elmLanguageConfig +> { public constructor() { super(elmLanguageConfig); } @@ -43,7 +55,14 @@ export class ElmTargetLanguage extends TargetLanguage return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): ElmRenderer { - return new ElmRenderer(this, renderContext, getOptionValues(elmOptions, untypedOptionValues)); + protected makeRenderer( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index 51f9d962..31cb0b62 100644 --- a/packages/quicktype-core/src/language/Elm/utils.ts +++ b/packages/quicktype-core/src/language/Elm/utils.ts @@ -8,12 +8,14 @@ import { isLetterOrUnderscore, isLetterOrUnderscoreOrDigit, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../../support/Strings"; import { type ClassProperty, UnionType } from "../../Type"; import { nullableFromUnion } from "../../Type/TypeUtils"; -const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); +const legalizeName = legalizeCharacters( + (cp) => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp), +); function elmNameStyle(original: string, upper: boolean): string { const words = splitIntoWords(original); @@ -25,12 +27,16 @@ function elmNameStyle(original: string, upper: boolean): string { upper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } -export const upperNamingFunction = funPrefixNamer("upper", n => elmNameStyle(n, true)); -export const lowerNamingFunction = funPrefixNamer("lower", n => elmNameStyle(n, false)); +export const upperNamingFunction = funPrefixNamer("upper", (n) => + elmNameStyle(n, true), +); +export const lowerNamingFunction = funPrefixNamer("lower", (n) => + elmNameStyle(n, false), +); interface RequiredOrOptional { fallback: string; @@ -43,7 +49,10 @@ export function requiredOrOptional(p: ClassProperty): RequiredOrOptional { } 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"); } diff --git a/packages/quicktype-core/src/language/Golang/GolangRenderer.ts b/packages/quicktype-core/src/language/Golang/GolangRenderer.ts index a37eadb5..7dccdb03 100644 --- a/packages/quicktype-core/src/language/Golang/GolangRenderer.ts +++ b/packages/quicktype-core/src/language/Golang/GolangRenderer.ts @@ -1,17 +1,37 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; +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 { 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 "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import { + type ClassProperty, + type ClassType, + type EnumType, + type Type, + type TypeKind, + UnionType, +} from "../../Type"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; -import { type goOptions } from "./language"; -import { canOmitEmpty, compoundTypeKinds, isValueType, namingFunction, primitiveValueTypeKinds } from "./utils"; +import type { goOptions } from "./language"; +import { + canOmitEmpty, + compoundTypeKinds, + isValueType, + namingFunction, + primitiveValueTypeKinds, +} from "./utils"; export class GoRenderer extends ConvenienceRenderer { private readonly _topLevelUnmarshalNames = new Map(); @@ -21,7 +41,7 @@ export class GoRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -46,11 +66,14 @@ export class GoRenderer extends ConvenienceRenderer { 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]; @@ -62,7 +85,10 @@ export class GoRenderer extends ConvenienceRenderer { return; } - assert(this._currentFilename === undefined, "Previous file wasn't finished: " + this._currentFilename); + assert( + this._currentFilename === undefined, + `Previous file wasn't finished: ${this._currentFilename}`, + ); this._currentFilename = `${this.sourcelikeToString(basename)}.go`; this.initializeEmitContextForFilename(this._currentFilename); } @@ -95,9 +121,9 @@ export class GoRenderer extends ConvenienceRenderer { const goType = this.goType(t, withIssues); if (isValueType(t)) { return ["*", goType]; - } else { - return goType; } + + return goType; } private propertyGoType(cp: ClassProperty): Sourcelike { @@ -116,15 +142,25 @@ export class GoRenderer extends ConvenienceRenderer { private goType(t: Type, withIssues = false): Sourcelike { return matchType( t, - _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "interface{}"), - _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, "interface{}"), - _boolType => "bool", - _integerType => "int64", - _doubleType => "float64", - _stringType => "string", - arrayType => ["[]", this.goType(arrayType.items, withIssues)], - classType => this.nameForNamedType(classType), - mapType => { + (_anyType) => + maybeAnnotated( + withIssues, + anyTypeIssueAnnotation, + "interface{}", + ), + (_nullType) => + maybeAnnotated( + withIssues, + nullTypeIssueAnnotation, + "interface{}", + ), + (_boolType) => "bool", + (_integerType) => "int64", + (_doubleType) => "float64", + (_stringType) => "string", + (arrayType) => ["[]", this.goType(arrayType.items, withIssues)], + (classType) => this.nameForNamedType(classType), + (mapType) => { let valueSource: Sourcelike; const v = mapType.values; if (v instanceof UnionType && nullableFromUnion(v) === null) { @@ -135,19 +171,20 @@ export class GoRenderer extends ConvenienceRenderer { return ["map[string]", valueSource]; }, - enumType => this.nameForNamedType(enumType), - unionType => { + (enumType) => this.nameForNamedType(enumType), + (unionType) => { const nullable = nullableFromUnion(unionType); - if (nullable !== null) return this.nullableGoType(nullable, withIssues); + if (nullable !== null) + return this.nullableGoType(nullable, withIssues); return this.nameForNamedType(unionType); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return "time.Time"; } return "string"; - } + }, ); } @@ -161,12 +198,20 @@ export class GoRenderer extends ConvenienceRenderer { this.leadingComments === undefined ) { this.emitLineOnce( - "// Code generated from JSON Schema using quicktype. DO NOT EDIT." + "// Code generated from JSON Schema using quicktype. DO NOT EDIT.", + ); + this.emitLineOnce( + "// To parse and unparse this JSON data, add this code to your project and do:", ); - this.emitLineOnce("// To parse and unparse this JSON data, add this code to your project and do:"); this.emitLineOnce("//"); const ref = modifySource(camelCase, name); - this.emitLineOnce("// ", ref, ", err := ", defined(this._topLevelUnmarshalNames.get(name)), "(bytes)"); + this.emitLineOnce( + "// ", + ref, + ", err := ", + defined(this._topLevelUnmarshalNames.get(name)), + "(bytes)", + ); this.emitLineOnce("// bytes, err = ", ref, ".Marshal()"); } @@ -177,14 +222,18 @@ export class GoRenderer extends ConvenienceRenderer { this.emitLine("type ", name, " ", this.goType(t)); } - if (this._options.justTypes || this._options.justTypesAndPackage) return; + if (this._options.justTypes || this._options.justTypesAndPackage) + return; this.ensureBlankLine(); - this.emitFunc([unmarshalName, "(data []byte) (", name, ", error)"], () => { - this.emitLine("var r ", name); - this.emitLine("err := json.Unmarshal(data, &r)"); - this.emitLine("return r, err"); - }); + this.emitFunc( + [unmarshalName, "(data []byte) (", name, ", error)"], + () => { + this.emitLine("var r ", name); + this.emitLine("err := json.Unmarshal(data, &r)"); + this.emitLine("return r, err"); + }, + ); this.ensureBlankLine(); this.emitFunc(["(r *", name, ") Marshal() ([]byte, error)"], () => { this.emitLine("return json.Marshal(r)"); @@ -194,33 +243,39 @@ export class GoRenderer extends ConvenienceRenderer { private emitClass(c: ClassType, className: Name): void { this.startFile(className); - let columns: Sourcelike[][] = []; + const columns: Sourcelike[][] = []; const usedTypes = new Set(); this.forEachClassProperty(c, "none", (name, jsonName, p) => { const description = this.descriptionForClassProperty(c, jsonName); const docStrings = - description !== undefined && description.length > 0 ? description.map(d => "// " + d) : []; + description !== undefined && description.length > 0 + ? description.map((d) => "// " + d) + : []; const goType = this.propertyGoType(p); - const omitEmpty = canOmitEmpty(p, this._options.omitEmpty) ? ",omitempty" : []; + const omitEmpty = canOmitEmpty(p, this._options.omitEmpty) + ? ",omitempty" + : []; - docStrings.forEach(doc => columns.push([doc])); + 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()); }); this.emitPackageDefinitons( false, - usedTypes.has("time.Time") || usedTypes.has("*,time.Time") || usedTypes.has("[],time.Time") + 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); @@ -234,11 +289,11 @@ export class GoRenderer extends ConvenienceRenderer { this.emitLine("type ", enumName, " string"); this.ensureBlankLine(); this.emitLine("const ("); - let columns: Sourcelike[][] = []; + const columns: Sourcelike[][] = []; this.forEachEnumCase(e, "none", (name, jsonName) => { columns.push([ [name, " "], - [enumName, ' = "', stringEscape(jsonName), '"'] + [enumName, ' = "', stringEscape(jsonName), '"'], ]); }); this.indent(() => this.emitTable(columns)); @@ -255,11 +310,15 @@ export class GoRenderer extends ConvenienceRenderer { const ifMember: ( kind: TypeKind, ifNotMember: U, - f: (t: Type, fieldName: Name, goType: Sourcelike) => T + f: (t: Type, fieldName: Name, goType: Sourcelike) => T, ) => T | U = (kind, ifNotMember, f) => { const maybeType = u.findMember(kind); if (maybeType === undefined) return ifNotMember; - return f(maybeType, this.nameForUnionMember(u, maybeType), this.goType(maybeType)); + return f( + maybeType, + this.nameForUnionMember(u, maybeType), + this.goType(maybeType), + ); }; const maybeAssignNil = (kind: TypeKind): void => { @@ -270,20 +329,27 @@ 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)), - ", " + 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)), - ", " + ifMember(kind, "false, nil", (t, fieldName, _) => + compoundArg(t.kind === "class", fieldName), + ), + ", ", ); } @@ -291,7 +357,7 @@ export class GoRenderer extends ConvenienceRenderer { return args; }; - let columns: Sourcelike[][] = []; + const columns: Sourcelike[][] = []; this.forEachUnionMember(u, nonNulls, "none", null, (fieldName, t) => { const goType = this.nullableGoType(t, true); columns.push([[fieldName, " "], goType]); @@ -299,70 +365,91 @@ export class GoRenderer extends ConvenienceRenderer { this.emitDescription(this.descriptionForType(u)); this.emitStruct(unionName, columns); - if (this._options.justTypes || this._options.justTypesAndPackage) return; + if (this._options.justTypes || this._options.justTypesAndPackage) + return; this.ensureBlankLine(); - this.emitFunc(["(x *", unionName, ") UnmarshalJSON(data []byte) error"], () => { - for (const kind of compoundTypeKinds) { - maybeAssignNil(kind); - } - - ifMember("class", undefined, (_1, _2, goType) => { - this.emitLine("var c ", goType); - }); - const args = makeArgs( - fn => ["&x.", fn], - (isClass, fn) => { - if (isClass) { - return "true, &c"; - } else { - return ["true, &x.", fn]; - } + this.emitFunc( + ["(x *", unionName, ") UnmarshalJSON(data []byte) error"], + () => { + for (const kind of compoundTypeKinds) { + maybeAssignNil(kind); } - ); - this.emitLine("object, err := unmarshalUnion(data, ", args, ")"); - this.emitBlock("if err != nil", () => { - this.emitLine("return err"); - }); - this.emitBlock("if object", () => { - ifMember("class", undefined, (_1, fieldName, _2) => { - this.emitLine("x.", fieldName, " = &c"); + + ifMember("class", undefined, (_1, _2, goType) => { + this.emitLine("var c ", goType); }); - }); - this.emitLine("return nil"); - }); + const args = makeArgs( + (fn) => ["&x.", fn], + (isClass, fn) => (isClass ? "true, &c" : ["true, &x.", fn]), + ); + this.emitLine( + "object, err := unmarshalUnion(data, ", + args, + ")", + ); + this.emitBlock("if err != nil", () => { + this.emitLine("return err"); + }); + this.emitBlock("if object", () => { + ifMember("class", undefined, (_1, fieldName, _2) => { + this.emitLine("x.", fieldName, " = &c"); + }); + }); + this.emitLine("return nil"); + }, + ); this.ensureBlankLine(); - this.emitFunc(["(x *", unionName, ") MarshalJSON() ([]byte, error)"], () => { - const args = makeArgs( - fn => ["x.", fn], - (_, fn) => ["x.", fn, " != nil, x.", fn] - ); - this.emitLine("return marshalUnion(", args, ")"); - }); + this.emitFunc( + ["(x *", unionName, ") MarshalJSON() ([]byte, error)"], + () => { + const args = makeArgs( + (fn) => ["x.", fn], + (_, fn) => ["x.", fn, " != nil, x.", fn], + ); + this.emitLine("return marshalUnion(", args, ")"); + }, + ); this.endFile(); } private emitSingleFileHeaderComments(): void { - this.emitLineOnce("// Code generated from JSON Schema using quicktype. DO NOT EDIT."); - this.emitLineOnce("// To parse and unparse this JSON data, add this code to your project and do:"); + this.emitLineOnce( + "// Code generated from JSON Schema using quicktype. DO NOT EDIT.", + ); + this.emitLineOnce( + "// To parse and unparse this JSON data, add this code to your project and do:", + ); this.forEachTopLevel("none", (_: Type, name: Name) => { this.emitLine("//"); const ref = modifySource(camelCase, name); - this.emitLine("// ", ref, ", err := ", defined(this._topLevelUnmarshalNames.get(name)), "(bytes)"); + this.emitLine( + "// ", + ref, + ", err := ", + defined(this._topLevelUnmarshalNames.get(name)), + "(bytes)", + ); this.emitLine("// bytes, err = ", ref, ".Marshal()"); }); } - 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; + const packageDeclaration = `package ${this._options.packageName}`; this.emitLineOnce(packageDeclaration); this.ensureBlankLine(); } if (!this._options.justTypes && !this._options.justTypesAndPackage) { - if (this.haveNamedUnions && this._options.multiFileOutput === false) { + if ( + this.haveNamedUnions && + this._options.multiFileOutput === false + ) { imports.add("bytes"); imports.add("errors"); } @@ -376,13 +463,15 @@ export class GoRenderer extends ConvenienceRenderer { } private emitImports(imports: Set): void { - const sortedImports = Array.from(imports).sort((a, b) => a.localeCompare(b)); + const sortedImports = Array.from(imports).sort((a, b) => + a.localeCompare(b), + ); if (sortedImports.length === 0) { return; } - sortedImports.forEach(packageName => { + sortedImports.forEach((packageName) => { this.emitLineOnce(`import "${packageName}"`); }); this.ensureBlankLine(); @@ -399,8 +488,7 @@ export class GoRenderer extends ConvenienceRenderer { this.emitPackageDefinitons(true, imports); 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) { + 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 } @@ -480,7 +568,6 @@ export class GoRenderer extends ConvenienceRenderer { 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) { @@ -531,13 +618,23 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, this.forEachTopLevel( "leading-and-interposing", (t, name) => this.emitTopLevel(t, name), - t => - !(this._options.justTypes || this._options.justTypesAndPackage) || - this.namedTypeToNameForTopLevel(t) === undefined + (t) => + !( + this._options.justTypes || this._options.justTypesAndPackage + ) || 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), + ); + this.forEachUnion( + "leading-and-interposing", + (u: UnionType, unionName: Name) => this.emitUnion(u, unionName), ); - 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)); - this.forEachUnion("leading-and-interposing", (u: UnionType, unionName: Name) => this.emitUnion(u, unionName)); if (this._options.justTypes || this._options.justTypesAndPackage) { return; @@ -548,15 +645,21 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, private collectAllImports(): Set { let imports = new Set(); - this.forEachObject("leading-and-interposing", (c: ClassType, _className: Name) => { - const classImports = this.collectClassImports(c); - imports = new Set([...imports, ...classImports]); - }); + this.forEachObject( + "leading-and-interposing", + (c: ClassType, _className: Name) => { + const classImports = this.collectClassImports(c); + imports = new Set([...imports, ...classImports]); + }, + ); - this.forEachUnion("leading-and-interposing", (u: UnionType, _unionName: Name) => { - const unionImports = this.collectUnionImports(u); - imports = new Set([...imports, ...unionImports]); - }); + this.forEachUnion( + "leading-and-interposing", + (u: UnionType, _unionName: Name) => { + const unionImports = this.collectUnionImports(u); + imports = new Set([...imports, ...unionImports]); + }, + ); return imports; } @@ -573,7 +676,7 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, }); const imports = new Set(); - usedTypes.forEach(k => { + usedTypes.forEach((k) => { const typeImport = mapping.get(k); if (typeImport) { imports.add(typeImport); @@ -595,14 +698,14 @@ func marshalUnion(pi *int64, pf *float64, pb *bool, ps *string, haveArray bool, }); const imports = new Set(); - usedTypes.forEach(k => { + for (const k of usedTypes) { const typeImport = mapping.get(k); if (!typeImport) { - return; + continue; } imports.add(typeImport); - }); + } return imports; } diff --git a/packages/quicktype-core/src/language/Golang/language.ts b/packages/quicktype-core/src/language/Golang/language.ts index bc295869..8c3a0740 100644 --- a/packages/quicktype-core/src/language/Golang/language.ts +++ b/packages/quicktype-core/src/language/Golang/language.ts @@ -1,32 +1,59 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; -import { type StringTypeMapping } from "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } 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"), + 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 - ) + false, + ), }; const golangLanguageConfig = { displayName: "Go", names: ["go", "golang"], - extension: "go" + extension: "go", } as const; -export class GoTargetLanguage extends TargetLanguage { +export class GoTargetLanguage extends TargetLanguage< + typeof golangLanguageConfig +> { public constructor() { super(golangLanguageConfig); } @@ -40,7 +67,8 @@ export class GoTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); mapping.set("date-time", "date-time"); return mapping; } @@ -49,8 +77,15 @@ export class GoTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): GoRenderer { + return new GoRenderer( + this, + renderContext, + getOptionValues(goOptions, untypedOptionValues), + ); } protected get defaultIndentation(): string { diff --git a/packages/quicktype-core/src/language/Golang/utils.ts b/packages/quicktype-core/src/language/Golang/utils.ts index ce67443a..b53ecd01 100644 --- a/packages/quicktype-core/src/language/Golang/utils.ts +++ b/packages/quicktype-core/src/language/Golang/utils.ts @@ -6,9 +6,9 @@ import { isLetterOrUnderscore, isLetterOrUnderscoreOrDigit, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../../support/Strings"; -import { type ClassProperty, type Type, type TypeKind } from "../../Type"; +import type { ClassProperty, Type, TypeKind } from "../../Type"; export const namingFunction = funPrefixNamer("namer", goNameStyle); @@ -24,19 +24,32 @@ function goNameStyle(original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } -export const primitiveValueTypeKinds: TypeKind[] = ["integer", "double", "bool", "string"]; +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.includes(kind) || 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 { +export function canOmitEmpty( + cp: ClassProperty, + omitEmptyOption: boolean, +): boolean { if (!cp.isOptional) return false; if (omitEmptyOption) return true; const t = cp.type; diff --git a/packages/quicktype-core/src/language/Haskell/HaskellRenderer.ts b/packages/quicktype-core/src/language/Haskell/HaskellRenderer.ts index a986ed24..7ad2e758 100644 --- a/packages/quicktype-core/src/language/Haskell/HaskellRenderer.ts +++ b/packages/quicktype-core/src/language/Haskell/HaskellRenderer.ts @@ -1,24 +1,39 @@ import { mapContains } from "collection-utils"; -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 { + ConvenienceRenderer, + type ForbiddenWordsInfo, +} from "../../ConvenienceRenderer"; +import type { Name, 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 type { TargetLanguage } from "../../TargetLanguage"; +import type { + ClassProperty, + ClassType, + EnumType, + Type, + UnionType, +} from "../../Type"; import { matchType, nullableFromUnion } from "../../Type/TypeUtils"; import { forbiddenNames } from "./constants"; -import { type haskellOptions } from "./language"; +import type { haskellOptions } from "./language"; import { lowerNamingFunction, upperNamingFunction } from "./utils"; export class HaskellRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -35,7 +50,10 @@ export class HaskellRenderer extends ConvenienceRenderer { return lowerNamingFunction; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { + protected forbiddenForObjectProperties( + _c: ClassType, + _className: Name, + ): ForbiddenWordsInfo { return { names: [], includeGlobalForbidden: true }; } @@ -59,9 +77,14 @@ export class HaskellRenderer extends ConvenienceRenderer { u: UnionType, unionName: Name, fieldType: Type, - lookup: (n: Name) => string + lookup: (n: Name) => string, ): string { - const fieldName = super.proposeUnionMemberName(u, unionName, fieldType, lookup); + const fieldName = super.proposeUnionMemberName( + u, + unionName, + fieldType, + lookup, + ); return `${fieldName}_in_${lookup(unionName)}`; } @@ -71,12 +94,14 @@ export class HaskellRenderer extends ConvenienceRenderer { protected emitDescriptionBlock(lines: Sourcelike[]): void { if (lines.length === 1) { - this.emitComments([{ customLines: lines, lineStart: "{-| ", lineEnd: " -}" }]); + this.emitComments([ + { customLines: lines, lineStart: "{-| ", lineEnd: " -}" }, + ]); } else { this.emitCommentLines(lines, { firstLineStart: "{-| ", lineStart: "", - afterComment: "-}" + afterComment: "-}", }); } } @@ -84,23 +109,37 @@ export class HaskellRenderer extends ConvenienceRenderer { private haskellType(t: Type, noOptional = false): MultiWord { return matchType( t, - _anyType => multiWord(" ", "Maybe", "Text"), - _nullType => multiWord(" ", "Maybe", "Text"), - _boolType => singleWord("Bool"), - _integerType => singleWord("Int"), - _doubleType => singleWord("Float"), - _stringType => singleWord("Text"), - arrayType => { + (_anyType) => multiWord(" ", "Maybe", "Text"), + (_nullType) => multiWord(" ", "Maybe", "Text"), + (_boolType) => singleWord("Bool"), + (_integerType) => singleWord("Int"), + (_doubleType) => singleWord("Float"), + (_stringType) => singleWord("Text"), + (arrayType) => { if (this._options.useList) { - return multiWord("", "[", parenIfNeeded(this.haskellType(arrayType.items)), "]"); + return multiWord( + "", + "[", + parenIfNeeded(this.haskellType(arrayType.items)), + "]", + ); } - return multiWord(" ", "Vector", parenIfNeeded(this.haskellType(arrayType.items))); + return multiWord( + " ", + "Vector", + parenIfNeeded(this.haskellType(arrayType.items)), + ); }, - classType => singleWord(this.nameForNamedType(classType)), - mapType => multiWord(" ", "HashMap Text", parenIfNeeded(this.haskellType(mapType.values))), - enumType => singleWord(this.nameForNamedType(enumType)), - unionType => { + (classType) => singleWord(this.nameForNamedType(classType)), + (mapType) => + multiWord( + " ", + "HashMap Text", + parenIfNeeded(this.haskellType(mapType.values)), + ), + (enumType) => singleWord(this.nameForNamedType(enumType)), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { const nullableType = this.haskellType(nullable); @@ -109,32 +148,36 @@ export class HaskellRenderer extends ConvenienceRenderer { } return singleWord(this.nameForNamedType(unionType)); - } + }, ); } private haskellProperty(p: ClassProperty): Sourcelike { if (p.isOptional) { - return multiWord(" ", "Maybe", parenIfNeeded(this.haskellType(p.type, true))).source; - } else { - return this.haskellType(p.type).source; + return multiWord( + " ", + "Maybe", + parenIfNeeded(this.haskellType(p.type, true)), + ).source; } + + return this.haskellType(p.type).source; } private encoderNameForType(t: Type): MultiWord { return matchType( t, - _anyType => singleWord("String"), - _nullType => singleWord("Null"), - _boolType => singleWord("Bool"), - _integerType => singleWord("Number"), - _doubleType => singleWord("Number"), - _stringType => singleWord("String"), - _arrayType => singleWord("Array"), - _classType => singleWord("Object"), - _mapType => singleWord("Object"), - _enumType => singleWord("Object"), - _unionType => singleWord("Object") + (_anyType) => singleWord("String"), + (_nullType) => singleWord("Null"), + (_boolType) => singleWord("Bool"), + (_integerType) => singleWord("Number"), + (_doubleType) => singleWord("Number"), + (_stringType) => singleWord("String"), + (_arrayType) => singleWord("Array"), + (_classType) => singleWord("Object"), + (_mapType) => singleWord("Object"), + (_enumType) => singleWord("Object"), + (_unionType) => singleWord("Object"), ); } @@ -145,7 +188,10 @@ export class HaskellRenderer extends ConvenienceRenderer { private emitClassDefinition(c: ClassType, className: Name): void { let description = this.descriptionForType(c); this.forEachClassProperty(c, "none", (name, jsonName) => { - const propertyDescription = this.descriptionForClassProperty(c, jsonName); + const propertyDescription = this.descriptionForClassProperty( + c, + jsonName, + ); if (propertyDescription === undefined) return; if (description === undefined) { @@ -163,7 +209,13 @@ export class HaskellRenderer extends ConvenienceRenderer { this.indent(() => { let onFirst = true; this.forEachClassProperty(c, "none", (name, _jsonName, p) => { - this.emitLine(onFirst ? "{ " : ", ", name, className, " :: ", this.haskellProperty(p)); + this.emitLine( + onFirst ? "{ " : ", ", + name, + className, + " :: ", + this.haskellProperty(p), + ); onFirst = false; }); if (onFirst) { @@ -179,7 +231,7 @@ export class HaskellRenderer extends ConvenienceRenderer { this.emitLine("data ", enumName); this.indent(() => { let onFirst = true; - this.forEachEnumCase(e, "none", name => { + this.forEachEnumCase(e, "none", (name) => { const equalsOrPipe = onFirst ? "=" : "|"; this.emitLine(equalsOrPipe, " ", name, enumName); onFirst = false; @@ -193,12 +245,18 @@ export class HaskellRenderer extends ConvenienceRenderer { this.emitLine("data ", unionName); this.indent(() => { let onFirst = true; - this.forEachUnionMember(u, null, "none", null, (constructor, t) => { + this.forEachUnionMember(u, null, "none", null, (name, t) => { const equalsOrPipe = onFirst ? "=" : "|"; if (t.kind === "null") { - this.emitLine(equalsOrPipe, " ", constructor); + this.emitLine(equalsOrPipe, " ", name); } else { - this.emitLine(equalsOrPipe, " ", constructor, " ", parenIfNeeded(this.haskellType(t))); + this.emitLine( + equalsOrPipe, + " ", + name, + " ", + parenIfNeeded(this.haskellType(t)), + ); } onFirst = false; @@ -221,8 +279,8 @@ export class HaskellRenderer extends ConvenienceRenderer { } private emitClassEncoderInstance(c: ClassType, className: Name): void { - let classProperties: Array = []; - this.forEachClassProperty(c, "none", name => { + const classProperties: Array = []; + this.forEachClassProperty(c, "none", (name) => { classProperties.push(" "); classProperties.push(name); classProperties.push(className); @@ -238,7 +296,14 @@ 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) { @@ -263,7 +328,14 @@ 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; }); }); @@ -281,7 +353,14 @@ export class HaskellRenderer extends ConvenienceRenderer { 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), + '"', + ); }); }); } @@ -294,7 +373,13 @@ export class HaskellRenderer extends ConvenienceRenderer { 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, + ); }); }); }); @@ -310,11 +395,11 @@ export class HaskellRenderer extends ConvenienceRenderer { private emitUnionEncoderInstance(u: UnionType, unionName: Name): void { this.emitLine("instance ToJSON ", unionName, " where"); this.indent(() => { - this.forEachUnionMember(u, null, "none", null, (constructor, t) => { + this.forEachUnionMember(u, null, "none", null, (name, t) => { if (t.kind === "null") { - this.emitLine("toJSON ", constructor, " = Null"); + this.emitLine("toJSON ", name, " = Null"); } else { - this.emitLine("toJSON (", constructor, " x) = toJSON x"); + this.emitLine("toJSON (", name, " x) = toJSON x"); } }); }); @@ -323,16 +408,16 @@ export class HaskellRenderer extends ConvenienceRenderer { private emitUnionDecoderInstance(u: UnionType, unionName: Name): void { this.emitLine("instance FromJSON ", unionName, " where"); this.indent(() => { - this.forEachUnionMember(u, null, "none", null, (constructor, t) => { + this.forEachUnionMember(u, null, "none", null, (name, t) => { if (t.kind === "null") { - this.emitLine("parseJSON Null = return ", constructor); + this.emitLine("parseJSON Null = return ", name); } else { this.emitLine( "parseJSON xs@(", this.encoderNameForType(t).source, " _) = (fmap ", - constructor, - " . parseJSON) xs" + name, + " . parseJSON) xs", ); } }); @@ -393,26 +478,35 @@ import Data.Text (Text)`); this.forEachTopLevel( "leading-and-interposing", - (t: Type, topLevelName: Name) => this.emitTopLevelDefinition(t, topLevelName), - t => this.namedTypeToNameForTopLevel(t) === undefined + (t: Type, topLevelName: Name) => + this.emitTopLevelDefinition(t, topLevelName), + (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) + (c: ClassType, className: Name) => + this.emitClassDefinition(c, className), + (e: EnumType, enumName: Name) => + this.emitEnumDefinition(e, enumName), + (u: UnionType, unionName: Name) => + this.emitUnionDefinition(u, unionName), ); - this.forEachTopLevel("leading-and-interposing", (_: Type, topLevelName: Name) => - this.emitTopLevelFunctions(topLevelName) + this.forEachTopLevel( + "leading-and-interposing", + (_: Type, topLevelName: Name) => + 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) + (c: ClassType, className: Name) => + this.emitClassFunctions(c, className), + (e: EnumType, enumName: Name) => + this.emitEnumFunctions(e, enumName), + (u: UnionType, unionName: Name) => + this.emitUnionFunctions(u, unionName), ); if (this._options.justTypes) return; diff --git a/packages/quicktype-core/src/language/Haskell/constants.ts b/packages/quicktype-core/src/language/Haskell/constants.ts index 5e09e670..e4eee6e5 100644 --- a/packages/quicktype-core/src/language/Haskell/constants.ts +++ b/packages/quicktype-core/src/language/Haskell/constants.ts @@ -50,5 +50,5 @@ export const forbiddenNames = [ "Object", "Result", "Series", - "Error" + "Error", ] as const; diff --git a/packages/quicktype-core/src/language/Haskell/language.ts b/packages/quicktype-core/src/language/Haskell/language.ts index e7c35f9c..58638b03 100644 --- a/packages/quicktype-core/src/language/Haskell/language.ts +++ b/packages/quicktype-core/src/language/Haskell/language.ts @@ -1,7 +1,12 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { HaskellRenderer } from "./HaskellRenderer"; @@ -12,20 +17,27 @@ export const haskellOptions = { "Use Array or List", { array: false, - list: true + list: true, } as const, - "array" + "array", + ), + moduleName: new StringOption( + "module", + "Generated module name", + "NAME", + "QuickType", ), - moduleName: new StringOption("module", "Generated module name", "NAME", "QuickType") }; export const haskellLanguageConfig = { displayName: "Haskell", names: ["haskell"], - extension: "haskell" + extension: "haskell", } as const; -export class HaskellTargetLanguage extends TargetLanguage { +export class HaskellTargetLanguage extends TargetLanguage< + typeof haskellLanguageConfig +> { public constructor() { super(haskellLanguageConfig); } @@ -42,7 +54,14 @@ export class HaskellTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index 3f4b1357..d7106757 100644 --- a/packages/quicktype-core/src/language/Haskell/utils.ts +++ b/packages/quicktype-core/src/language/Haskell/utils.ts @@ -8,10 +8,12 @@ import { isLetterOrUnderscore, isLetterOrUnderscoreOrDigit, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../../support/Strings"; -const legalizeName = legalizeCharacters(cp => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp)); +const legalizeName = legalizeCharacters( + (cp) => isAscii(cp) && isLetterOrUnderscoreOrDigit(cp), +); function haskellNameStyle(original: string, upper: boolean): string { const words = splitIntoWords(original); @@ -23,9 +25,13 @@ function haskellNameStyle(original: string, upper: boolean): string { upper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } -export const upperNamingFunction = funPrefixNamer("upper", n => haskellNameStyle(n, true)); -export const lowerNamingFunction = funPrefixNamer("lower", n => haskellNameStyle(n, false)); +export const upperNamingFunction = funPrefixNamer("upper", (n) => + haskellNameStyle(n, true), +); +export const lowerNamingFunction = funPrefixNamer("lower", (n) => + haskellNameStyle(n, false), +); diff --git a/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts b/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts index dced5941..2f2aca5d 100644 --- a/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts +++ b/packages/quicktype-core/src/language/JSONSchema/JSONSchemaRenderer.ts @@ -2,14 +2,14 @@ import { iterableFirst, mapFirst } from "collection-utils"; import { addDescriptionToSchema } from "../../attributes/Description"; import { ConvenienceRenderer } from "../../ConvenienceRenderer"; -import { type Name, type Namer } from "../../Naming"; +import type { Name, Namer } from "../../Naming"; import { defined, panic } from "../../support/Support"; import { type EnumType, type ObjectType, type Type, type UnionType, - transformedStringTypeTargetTypeKindsMap + transformedStringTypeTargetTypeKindsMap, } from "../../Type"; import { matchTypeExhaustive } from "../../Type/TypeUtils"; @@ -51,7 +51,9 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { return this.schemaForType(first); } - return { anyOf: Array.from(types).map((t: Type) => this.schemaForType(t)) }; + return { + anyOf: Array.from(types).map((t: Type) => this.schemaForType(t)), + }; } private makeRef(t: Type): Schema { @@ -68,35 +70,42 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { private schemaForType(t: Type): Schema { const schema = matchTypeExhaustive( t, - _noneType => { + (_noneType) => { return panic("none type should have been replaced"); }, - _anyType => ({}), - _nullType => ({ type: "null" }), - _boolType => ({ type: "boolean" }), - _integerType => ({ type: "integer" }), - _doubleType => ({ type: "number" }), - _stringType => ({ type: "string" }), - arrayType => ({ type: "array", items: this.schemaForType(arrayType.items) }), - classType => this.makeRef(classType), - mapType => this.definitionForObject(mapType, undefined), - objectType => this.makeRef(objectType), - enumType => this.makeRef(enumType), - unionType => { + (_anyType) => ({}), + (_nullType) => ({ type: "null" }), + (_boolType) => ({ type: "boolean" }), + (_integerType) => ({ type: "integer" }), + (_doubleType) => ({ type: "number" }), + (_stringType) => ({ type: "string" }), + (arrayType) => ({ + type: "array", + items: this.schemaForType(arrayType.items), + }), + (classType) => this.makeRef(classType), + (mapType) => this.definitionForObject(mapType, undefined), + (objectType) => this.makeRef(objectType), + (enumType) => this.makeRef(enumType), + (unionType) => { if (this.unionNeedsName(unionType)) { return this.makeRef(unionType); - } else { - return this.definitionForUnion(unionType); } + + return this.definitionForUnion(unionType); }, - transformedStringType => { - const target = transformedStringTypeTargetTypeKindsMap.get(transformedStringType.kind); + (transformedStringType) => { + const target = transformedStringTypeTargetTypeKindsMap.get( + transformedStringType.kind, + ); if (target === undefined) { - return panic(`Unknown transformed string type ${transformedStringType.kind}`); + return panic( + `Unknown transformed string type ${transformedStringType.kind}`, + ); } return { type: "string", format: target.jsonSchema }; - } + }, ); if (schema.$ref === undefined) { this.addAttributesToSchema(t, schema); @@ -105,7 +114,10 @@ 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) { @@ -117,7 +129,10 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { for (const [name, p] of o.getProperties()) { const prop = this.schemaForType(p.type); if (prop.description === undefined) { - addDescriptionToSchema(prop, this.descriptionForClassProperty(o, name)); + addDescriptionToSchema( + prop, + this.descriptionForClassProperty(o, name), + ); } props[name] = prop; @@ -131,13 +146,14 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { } const additional = o.getAdditionalProperties(); - const additionalProperties = additional !== undefined ? this.schemaForType(additional) : false; + const additionalProperties = + additional !== undefined ? this.schemaForType(additional) : false; const schema = { type: "object", additionalProperties, properties, required, - title + title, }; this.addAttributesToSchema(o, schema); return schema; @@ -161,8 +177,14 @@ export class JSONSchemaRenderer extends ConvenienceRenderer { 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 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 } = {}; this.forEachObject("none", (o: ObjectType, name: Name) => { const title = defined(this.names.get(name)); diff --git a/packages/quicktype-core/src/language/JSONSchema/language.ts b/packages/quicktype-core/src/language/JSONSchema/language.ts index 30e497e2..6a371de5 100644 --- a/packages/quicktype-core/src/language/JSONSchema/language.ts +++ b/packages/quicktype-core/src/language/JSONSchema/language.ts @@ -1,17 +1,22 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { TargetLanguage } from "../../TargetLanguage"; -import { type StringTypeMapping, getNoStringTypeMapping } from "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import { + type StringTypeMapping, + getNoStringTypeMapping, +} from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } from "../../types"; import { JSONSchemaRenderer } from "./JSONSchemaRenderer"; export const JSONSchemaLanguageConfig = { displayName: "JSON Schema", names: ["schema", "json-schema"], - extension: "schema" + extension: "schema", } as const; -export class JSONSchemaTargetLanguage extends TargetLanguage { +export class JSONSchemaTargetLanguage extends TargetLanguage< + typeof JSONSchemaLanguageConfig +> { public constructor() { super(JSONSchemaLanguageConfig); } @@ -32,7 +37,10 @@ export class JSONSchemaTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + _untypedOptionValues: RendererOptions, + ): 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 index 5c3a10e4..32f65b51 100644 --- a/packages/quicktype-core/src/language/JSONSchema/utils.ts +++ b/packages/quicktype-core/src/language/JSONSchema/utils.ts @@ -4,12 +4,14 @@ import { combineWords, firstUpperWordStyle, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../../support/Strings"; export const namingFunction = funPrefixNamer("namer", jsonNameStyle); -const legalizeName = legalizeCharacters(cp => cp >= 32 && cp < 128 && cp !== 0x2f /* slash */); +const legalizeName = legalizeCharacters( + (cp) => cp >= 32 && cp < 128 && cp !== 0x2f /* slash */, +); function jsonNameStyle(original: string): string { const words = splitIntoWords(original); @@ -21,6 +23,6 @@ function jsonNameStyle(original: string): string { allUpperWordStyle, allUpperWordStyle, "", - _ => true + (_) => true, ); } diff --git a/packages/quicktype-core/src/language/Java/DateTimeProvider.ts b/packages/quicktype-core/src/language/Java/DateTimeProvider.ts index 78228db0..e1e4d3c7 100644 --- a/packages/quicktype-core/src/language/Java/DateTimeProvider.ts +++ b/packages/quicktype-core/src/language/Java/DateTimeProvider.ts @@ -1,11 +1,11 @@ -import { type Sourcelike } from "../../Source"; +import type { Sourcelike } from "../../Source"; -import { type JavaRenderer } from "./JavaRenderer"; +import type { JavaRenderer } from "./JavaRenderer"; export abstract class JavaDateTimeProvider { public constructor( protected readonly _renderer: JavaRenderer, - protected readonly _className: string + protected readonly _className: string, ) {} public abstract keywords: string[]; @@ -56,7 +56,7 @@ export class Java8DateTimeProvider extends JavaDateTimeProvider { "ZonedDateTime", "DateTimeFormatter", "DateTimeFormatterBuilder", - "ChronoField" + "ChronoField", ]; public dateTimeImports: string[] = ["java.time.OffsetDateTime"]; @@ -73,7 +73,7 @@ export class Java8DateTimeProvider extends JavaDateTimeProvider { "java.time.ZonedDateTime", "java.time.format.DateTimeFormatter", "java.time.format.DateTimeFormatterBuilder", - "java.time.temporal.ChronoField" + "java.time.temporal.ChronoField", ]; public dateTimeType = "OffsetDateTime"; @@ -91,48 +91,76 @@ export class Java8DateTimeProvider extends JavaDateTimeProvider { 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.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.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()" + "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( + ".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();" - ); - }); + 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 { @@ -148,15 +176,24 @@ export class Java8DateTimeProvider extends JavaDateTimeProvider { } public convertDateTimeToString(variable: Sourcelike): Sourcelike { - return [variable, ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)"]; + 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)"]; + return [ + variable, + ".format(java.time.format.DateTimeFormatter.ISO_OFFSET_TIME)", + ]; } public convertDateToString(variable: Sourcelike): Sourcelike { - return [variable, ".format(java.time.format.DateTimeFormatter.ISO_DATE)"]; + return [ + variable, + ".format(java.time.format.DateTimeFormatter.ISO_DATE)", + ]; } } export class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { @@ -168,7 +205,10 @@ export class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { public timeImports: string[] = ["java.util.Date"]; - public converterImports: string[] = ["java.util.Date", "java.text.SimpleDateFormat"]; + public converterImports: string[] = [ + "java.util.Date", + "java.text.SimpleDateFormat", + ]; public dateTimeType = "Date"; @@ -177,12 +217,16 @@ export class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { public timeType = "Date"; public dateTimeJacksonAnnotations: string[] = [ - '@JsonFormat(pattern = "yyyy-MM-dd\'T\'HH:mm:ssX", timezone = "UTC")' + '@JsonFormat(pattern = "yyyy-MM-dd\'T\'HH:mm:ssX", timezone = "UTC")', ]; - public dateJacksonAnnotations: string[] = ['@JsonFormat(pattern = "yyyy-MM-dd")']; + public dateJacksonAnnotations: string[] = [ + '@JsonFormat(pattern = "yyyy-MM-dd")', + ]; - public timeJacksonAnnotations: string[] = ['@JsonFormat(pattern = "HH:mm:ssX", timezone = "UTC")']; + public timeJacksonAnnotations: string[] = [ + '@JsonFormat(pattern = "HH:mm:ssX", timezone = "UTC")', + ]; public shouldEmitTimeConverter = false; @@ -190,7 +234,9 @@ export class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { public emitDateTimeConverters(): void { this._renderer.ensureBlankLine(); - this._renderer.emitLine("private static final String[] DATE_TIME_FORMATS = {"); + 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\","); @@ -206,33 +252,56 @@ export class JavaLegacyDateTimeProvider extends JavaDateTimeProvider { 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.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.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.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);'); - }); + 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 { diff --git a/packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts b/packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts index 560adadd..721bada4 100644 --- a/packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts +++ b/packages/quicktype-core/src/language/Java/JavaJacksonRenderer.ts @@ -1,567 +1,799 @@ -import { type Name } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { type OptionValues } from "../../RendererOptions"; -import { type Sourcelike } from "../../Source"; +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 type { TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + type Type, + type TypeKind, + UnionType, +} from "../../Type"; import { removeNullFromUnion } from "../../Type/TypeUtils"; import { JavaRenderer } from "./JavaRenderer"; -import { type javaOptions } from "./language"; +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); - } + 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 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)"); + protected emitClassAttributes(c: ClassType, _className: Name): void { + if (c.getProperties().size === 0) + this.emitLine( + "@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.NONE)", + ); - super.emitClassAttributes(c, _className); - } + 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); + 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) + '")']; + 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; - } + 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]; - } + 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; - } + 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.*"); - } + 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; - } + return imports; + } - if (t instanceof EnumType) { - const imports = super.importsForType(t); - imports.push("com.fasterxml.jackson.annotation.*"); - return imports; - } + if (t instanceof EnumType) { + const imports = super.importsForType(t); + imports.push("com.fasterxml.jackson.annotation.*"); + return imports; + } - return assertNever(t); - } + 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 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"]; + 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 tokenCase = (tokenType: string): void => { + this.emitLine("case ", tokenType, ":"); + }; - const emitNullDeserializer = (): void => { - this.indent(() => { - tokenCase("VALUE_NULL"); - this.indent(() => this.emitLine("break;")); - }); - }; + 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), - ";" - ); + 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 "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; + 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!"); - } - }; + break; + default: + 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 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; + 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(() => { + for (const tokenType of tokenTypes) { + tokenCase(tokenType); + } - this.indent(() => { - emitDeserializeType(t); - this.emitLine("break;"); - }); - }); - }; + this.indent(() => { + emitDeserializeType(t); + this.emitLine("break;"); + }); + }); + }; - const emitStringDeserializer = (): void => { - const enumType = u.findMember("enum"); - const stringType = u.findMember("string"); + 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; + if ( + stringBasedObjects.every( + (kind) => u.findMember(kind) === undefined, + ) && + stringType === undefined && + enumType === undefined + ) + return; - this.indent(() => { - tokenCase("VALUE_STRING"); + this.indent(() => { + tokenCase("VALUE_STRING"); - this.indent(() => { - const fromVariable = "string"; - this.emitLine("String " + fromVariable + " = jsonParser.readValueAs(String.class);"); + 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); - }); - } - }); + stringBasedObjects.forEach((kind) => { + const type = u.findMember(kind); + if (type !== undefined) { + this.emitIgnoredTryCatchBlock(() => { + emitDeserializeType(type, fromVariable); + }); + } + }); - if (enumType !== undefined) { - this.emitIgnoredTryCatchBlock(() => { - emitDeserializeType(enumType, 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); - } + // String should be the last one if exists, because it cannot fail, unlike the parsers. + if (stringType !== undefined) { + emitDeserializeType(stringType, fromVariable); + } - this.emitLine("break;"); - }); - }); - }; + this.emitLine("break;"); + }); + }); + }; - const emitNumberDeserializer = (): void => { - const integerType = u.findMember("integer"); - const doubleType = u.findMember("double"); - if (doubleType === undefined && integerType === undefined) return; + 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;"); - }); - } + 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;"); - }); - } - }); - }; + if (doubleType !== undefined) { + tokenCase("VALUE_NUMBER_FLOAT"); + this.indent(() => { + emitDeserializeType(doubleType); + this.emitLine("break;"); + }); + } + }); + }; - const customObjectSerializer: TypeKind[] = ["time", "date", "date-time"]; + 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 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); + const emitSerializeType = (t: Type): void => { + const { 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.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;"); - }); - }; + this.emitLine("return;"); + }); + }; - const [maybeNull, nonNulls] = removeNullFromUnion(u); + 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); - } + 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");'); - } - } - ); - }); - } + 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 emitEnumSerializationAttributes(_e: EnumType): void { + this.emitLine("@JsonValue"); + } - protected emitEnumDeserializationAttributes(_e: EnumType): void { - this.emitLine("@JsonCreator"); - } + protected emitEnumDeserializationAttributes(_e: EnumType): void { + this.emitLine("@JsonCreator"); + } - protected emitOffsetDateTimeConverterModule(): void { - this.emitLine("SimpleModule module = new SimpleModule();"); + 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.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.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("});"); - } + 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);"); - } + 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(`// + 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.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(); - } + 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(); - } + 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 index 7555be5f..5d24de99 100644 --- a/packages/quicktype-core/src/language/Java/JavaRenderer.ts +++ b/packages/quicktype-core/src/language/Java/JavaRenderer.ts @@ -1,25 +1,56 @@ -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 { + 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 } 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 "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + MapType, + type Type, + UnionType, +} from "../../Type"; +import { + directlyReachableSingleNamedType, + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { javaKeywords } from "./constants"; -import { Java8DateTimeProvider, type JavaDateTimeProvider, JavaLegacyDateTimeProvider } from "./DateTimeProvider"; -import { type javaOptions } from "./language"; +import { + Java8DateTimeProvider, + type JavaDateTimeProvider, + JavaLegacyDateTimeProvider, +} from "./DateTimeProvider"; +import type { javaOptions } from "./language"; import { javaNameStyle, stringEscape } from "./utils"; export class JavaRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; - private readonly _gettersAndSettersForPropertyName = new Map(); + private readonly _gettersAndSettersForPropertyName = new Map< + Name, + [Name, Name] + >(); private _haveEmittedLeadingComments = false; @@ -32,17 +63,23 @@ export class JavaRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues + 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); + this._dateTimeProvider = new JavaLegacyDateTimeProvider( + this, + this._converterClassname, + ); + break; + case "java8": + default: + this._dateTimeProvider = new Java8DateTimeProvider( + this, + this._converterClassname, + ); break; } } @@ -52,12 +89,15 @@ export class JavaRenderer extends ConvenienceRenderer { ...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 }; } @@ -93,17 +133,17 @@ export class JavaRenderer extends ConvenienceRenderer { _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]; } @@ -113,29 +153,53 @@ export class JavaRenderer extends ConvenienceRenderer { className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { - const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, 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)) + typeNamingFunction: funPrefixNamer("types", (n) => + javaNameStyle( + true, + false, + n, + acronymStyle(this._options.acronymStyle), + ), ), - propertyNamingFunction: funPrefixNamer("properties", n => - javaNameStyle(false, 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), + ), ), - enumCaseNamingFunction: funPrefixNamer("enum-cases", n => - 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; } @@ -143,7 +207,11 @@ 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]; } @@ -168,12 +236,18 @@ export class JavaRenderer extends ConvenienceRenderer { } protected startFile(basename: Sourcelike): void { - assert(this._currentFilename === undefined, "Previous file wasn't finished"); + 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) { + if ( + !this._haveEmittedLeadingComments && + this.leadingComments !== undefined + ) { this.emitComments(this.leadingComments); this.ensureBlankLine(); this._haveEmittedLeadingComments = true; @@ -200,7 +274,11 @@ export class JavaRenderer extends ConvenienceRenderer { } public emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + this.emitCommentLines(lines, { + lineStart: " * ", + beforeComment: "/**", + afterComment: " */", + }); } public emitBlock(line: Sourcelike, f: () => void): void { @@ -209,7 +287,11 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitLine("}"); } - public emitTryCatch(main: () => void, handler: () => void, exception = "Exception"): void { + public emitTryCatch( + main: () => void, + handler: () => void, + exception = "Exception", + ): void { this.emitLine("try {"); this.indent(main); this.emitLine("} catch (", exception, " ex) {"); @@ -221,31 +303,49 @@ export class JavaRenderer extends ConvenienceRenderer { 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"), - _stringType => "String", - arrayType => { + (_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), "[]"]; + return [ + "List<", + this.javaType(true, arrayType.items, withIssues), + ">", + ]; } + + return [ + this.javaType(false, arrayType.items, withIssues), + "[]", + ]; }, - classType => this.nameForNamedType(classType), - mapType => ["Map"], - enumType => this.nameForNamedType(enumType), - unionType => { + (classType) => this.nameForNamedType(classType), + (mapType) => [ + "Map", + ], + (enumType) => this.nameForNamedType(enumType), + (unionType) => { const nullable = nullableFromUnion(unionType); - if (nullable !== null) return this.javaType(true, nullable, withIssues); + if (nullable !== null) + return this.javaType(true, nullable, withIssues); return this.nameForNamedType(unionType); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "time") { return this._dateTimeProvider.timeType; } @@ -263,35 +363,40 @@ export class JavaRenderer extends ConvenienceRenderer { } return "String"; - } + }, ); } protected javaImport(t: Type): string[] { return matchType( t, - _anyType => [], - _nullType => [], - _boolType => [], - _integerType => [], - _doubleType => [], - _stringType => [], - arrayType => { + (_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)]; + return [ + ...this.javaImport(arrayType.items), + "java.util.List", + ]; } + + return [...this.javaImport(arrayType.items)]; }, - _classType => [], - mapType => [...this.javaImport(mapType.values), "java.util.Map"], - _enumType => [], - unionType => { + (_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))); + unionType.members.forEach((type) => + this.javaImport(type).forEach((imp) => imports.push(imp)), + ); return imports; }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "time") { return this._dateTimeProvider.timeImports; } @@ -309,7 +414,7 @@ export class JavaRenderer extends ConvenienceRenderer { } return []; - } + }, ); } @@ -317,18 +422,21 @@ export class JavaRenderer extends ConvenienceRenderer { 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); + + return [this.javaTypeWithoutGenerics(false, t.items), "[]"]; } + if (t instanceof MapType) { + return "Map"; + } + if (t instanceof UnionType) { + const nullable = nullableFromUnion(t); + if (nullable !== null) + return this.javaTypeWithoutGenerics(true, nullable); + return this.nameForNamedType(t); + } + + return this.javaType(reference, t); } protected emitClassAttributes(_c: ClassType, _className: Name): void { @@ -343,7 +451,7 @@ export class JavaRenderer extends ConvenienceRenderer { _propertyName: Name, _jsonName: string, _p: ClassProperty, - _isSetter: boolean + _isSetter: boolean, ): string[] { return []; } @@ -367,7 +475,7 @@ export class JavaRenderer extends ConvenienceRenderer { protected importsForClass(c: ClassType): string[] { const imports: string[] = []; this.forEachClassProperty(c, "none", (_name, _jsonName, p) => { - this.javaImport(p.type).forEach(imp => imports.push(imp)); + this.javaImport(p.type).forEach((imp) => imports.push(imp)); }); imports.sort(); return [...new Set(imports)]; @@ -377,54 +485,119 @@ export class JavaRenderer extends ConvenienceRenderer { const imports: string[] = []; const [, nonNulls] = removeNullFromUnion(u); this.forEachUnionMember(u, nonNulls, "none", null, (_fieldName, t) => { - this.javaImport(t).forEach(imp => imports.push(imp)); + 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)]; + const 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 ( + 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(", ") + "})"); + this.emitLine( + `@lombok.Getter(onMethod_ = {${getter.join(", ")}})`, + ); } if (setter.length !== 0) { - this.emitLine("@lombok.Setter(onMethod_ = {" + setter.join(", ") + "})"); + this.emitLine( + `@lombok.Setter(onMethod_ = {${setter.join(", ")}})`, + ); } } - this.emitLine("private ", this.javaType(false, p.type, true), " ", name, ";"); + 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.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 } { + 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"]; @@ -440,7 +613,10 @@ export class JavaRenderer extends ConvenienceRenderer { } protected emitUnionDefinition(u: UnionType, unionName: Name): void { - const imports = [...this.importsForType(u), ...this.importsForUnionMembers(u)]; + const imports = [ + ...this.importsForType(u), + ...this.importsForUnionMembers(u), + ]; this.emitFileHeader(unionName, imports); this.emitDescription(this.descriptionForType(u)); @@ -470,7 +646,7 @@ export class JavaRenderer extends ConvenienceRenderer { this.emitFileHeader(enumName, this.importsForType(e)); this.emitDescription(this.descriptionForType(e)); const caseNames: Sourcelike[] = []; - this.forEachEnumCase(e, "none", name => { + this.forEachEnumCase(e, "none", (name) => { if (caseNames.length > 0) caseNames.push(", "); caseNames.push(name); }); @@ -484,7 +660,13 @@ 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("}"); @@ -493,12 +675,29 @@ export class JavaRenderer extends ConvenienceRenderer { 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.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(); } @@ -508,7 +707,7 @@ export class JavaRenderer 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), ); } } diff --git a/packages/quicktype-core/src/language/Java/constants.ts b/packages/quicktype-core/src/language/Java/constants.ts index d1e2f797..c16c58cd 100644 --- a/packages/quicktype-core/src/language/Java/constants.ts +++ b/packages/quicktype-core/src/language/Java/constants.ts @@ -65,5 +65,5 @@ export const javaKeywords = [ "while", "null", "false", - "true" + "true", ] as const; diff --git a/packages/quicktype-core/src/language/Java/language.ts b/packages/quicktype-core/src/language/Java/language.ts index a1f3d2d1..e8bf57b8 100644 --- a/packages/quicktype-core/src/language/Java/language.ts +++ b/packages/quicktype-core/src/language/Java/language.ts @@ -1,37 +1,62 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + 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 "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } 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 } as const, "array"), + useList: new EnumOption( + "array-type", + "Use T[] or List", + { array: false, list: true } as const, + "array", + ), justTypes: new BooleanOption("just-types", "Plain types only", false), dateTimeProvider: new EnumOption( "datetime-provider", "Date time provider type", { java8: "java8", legacy: "legacy" } as const, - "java8" + "java8", ), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), // FIXME: Do this via a configurable named eventually. - packageName: new StringOption("package", "Generated package name", "NAME", "io.quicktype"), + 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 const javaLanguageConfig = { displayName: "Java", names: ["java"], - extension: "java" + extension: "java", } as const; -export class JavaTargetLanguage extends TargetLanguage { +export class JavaTargetLanguage extends TargetLanguage< + typeof javaLanguageConfig +> { public constructor() { super(javaLanguageConfig); } @@ -44,7 +69,10 @@ export class JavaTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): JavaRenderer { const options = getOptionValues(javaOptions, untypedOptionValues); if (options.justTypes) { return new JavaRenderer(this, renderContext, options); @@ -54,7 +82,8 @@ export class JavaTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); mapping.set("date", "date"); mapping.set("time", "time"); mapping.set("date-time", "date-time"); diff --git a/packages/quicktype-core/src/language/Java/utils.ts b/packages/quicktype-core/src/language/Java/utils.ts index abc461f4..8e27c72b 100644 --- a/packages/quicktype-core/src/language/Java/utils.ts +++ b/packages/quicktype-core/src/language/Java/utils.ts @@ -10,10 +10,12 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../../support/Strings"; -export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); +export const stringEscape = utf16ConcatMap( + escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape), +); function isStartCharacter(codePoint: number): boolean { if (codePoint === 0x5f) return true; // underscore @@ -21,7 +23,10 @@ function isStartCharacter(codePoint: number): boolean { } function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); + return ( + isStartCharacter(codePoint) || + (isAscii(codePoint) && isDigit(codePoint)) + ); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); @@ -30,17 +35,23 @@ 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( words, legalizeName, - upperUnderscore ? allUpperWordStyle : startWithUpper ? firstUpperWordStyle : allLowerWordStyle, + upperUnderscore + ? allUpperWordStyle + : startWithUpper + ? firstUpperWordStyle + : allLowerWordStyle, upperUnderscore ? allUpperWordStyle : firstUpperWordStyle, - upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, + upperUnderscore || startWithUpper + ? allUpperWordStyle + : allLowerWordStyle, acronymsStyle, upperUnderscore ? "_" : "", - isStartCharacter + isStartCharacter, ); } diff --git a/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts index 2220107a..daf63569 100644 --- a/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts +++ b/packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts @@ -2,8 +2,8 @@ import { arrayIntercalate } from "collection-utils"; import { ConvenienceRenderer } from "../../ConvenienceRenderer"; import { type Name, type Namer, funPrefixNamer } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { type OptionValues } from "../../RendererOptions"; +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"; @@ -14,14 +14,22 @@ import { combineWords, firstUpperWordStyle, splitIntoWords, - utf16StringEscape + utf16StringEscape, } 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 "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import type { + ClassProperty, + ClassType, + ObjectType, + Type, +} from "../../Type"; +import { + directlyReachableSingleNamedType, + matchType, +} from "../../Type/TypeUtils"; -import { type javaScriptOptions } from "./language"; +import type { javaScriptOptions } from "./language"; import { isES3IdentifierStart } from "./unicodeMaps"; import { legalizeName } from "./utils"; @@ -35,13 +43,13 @@ export interface JavaScriptTypeAnnotations { stringArray: string; } -const identityNamingFunction = funPrefixNamer("properties", s => s); +const identityNamingFunction = funPrefixNamer("properties", (s) => s); export class JavaScriptRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _jsOptions: OptionValues + private readonly _jsOptions: OptionValues, ) { super(targetLanguage, renderContext); } @@ -57,12 +65,12 @@ export class JavaScriptRenderer extends ConvenienceRenderer { upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isES3IdentifierStart + isES3IdentifierStart, ); } protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("types", s => this.nameStyle(s, true)); + return funPrefixNamer("types", (s) => this.nameStyle(s, true)); } protected namerForObjectProperty(): Namer { @@ -74,7 +82,7 @@ export class JavaScriptRenderer extends ConvenienceRenderer { } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enum-cases", s => this.nameStyle(s, true)); + return funPrefixNamer("enum-cases", (s) => this.nameStyle(s, true)); } protected namedTypeToNameForTopLevel(type: Type): Type | undefined { @@ -86,14 +94,18 @@ export class JavaScriptRenderer extends ConvenienceRenderer { 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 { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + this.emitCommentLines(lines, { + lineStart: " * ", + beforeComment: "/**", + afterComment: " */", + }); } private typeMapTypeFor(t: Type): Sourcelike { @@ -103,27 +115,29 @@ export class JavaScriptRenderer extends ConvenienceRenderer { return matchType( t, - _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), ")"], - _enumType => panic("We handled this above"), - unionType => { - const children = Array.from(unionType.getChildren()).map((type: Type) => this.typeMapTypeFor(type)); + (_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), ")"], + (_enumType) => panic("We handled this above"), + (unionType) => { + const children = Array.from(unionType.getChildren()).map( + (type: Type) => this.typeMapTypeFor(type), + ); return ["u(", ...arrayIntercalate(", ", children), ")"]; }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return "Date"; } return '""'; - } + }, ); } @@ -136,7 +150,11 @@ export class JavaScriptRenderer extends ConvenienceRenderer { return ["u(undefined, ", typeMap, ")"]; } - protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void): void { + protected emitBlock( + source: Sourcelike, + end: Sourcelike, + emit: () => void, + ): void { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); @@ -149,20 +167,26 @@ export class JavaScriptRenderer extends ConvenienceRenderer { this.forEachObject("none", (t: ObjectType, name: Name) => { const additionalProperties = t.getAdditionalProperties(); const additional = - additionalProperties !== undefined ? this.typeMapTypeFor(additionalProperties) : "false"; + additionalProperties !== undefined + ? this.typeMapTypeFor(additionalProperties) + : "false"; this.emitLine('"', name, '": o(['); this.indent(() => { - this.forEachClassProperty(t, "none", (propName, jsonName, property) => { - this.emitLine( - '{ json: "', - utf16StringEscape(jsonName), - '", js: "', - modifySource(utf16StringEscape, propName), - '", typ: ', - this.typeMapTypeForProperty(property), - " }," - ); - }); + this.forEachClassProperty( + t, + "none", + (propName, jsonName, property) => { + this.emitLine( + '{ json: "', + utf16StringEscape(jsonName), + '", js: "', + modifySource(utf16StringEscape, propName), + '", typ: ', + this.typeMapTypeForProperty(property), + " },", + ); + }, + ); }); this.emitLine("], ", additional, "),"); }); @@ -211,38 +235,63 @@ export class JavaScriptRenderer extends ConvenienceRenderer { string: "", stringArray: "", boolean: "", - never: "" + never: "", }; } protected emitConvertModuleBody(): void { 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"; - if (!this._jsOptions.runtimeTypecheck) { - this.emitLine("return ", parsedJson, ";"); - } else { - this.emitLine("return cast(", parsedJson, ", ", typeMap, ");"); - } - }); + this.emitBlock( + [this.deserializerFunctionLine(t, name), " "], + "", + () => { + const parsedJson = + this._jsOptions.rawType === "json" + ? "JSON.parse(json)" + : "json"; + if (!this._jsOptions.runtimeTypecheck) { + this.emitLine("return ", parsedJson, ";"); + } else { + this.emitLine( + "return cast(", + parsedJson, + ", ", + typeMap, + ");", + ); + } + }, + ); this.ensureBlankLine(); - this.emitBlock([this.serializerFunctionLine(t, name), " "], "", () => { - if (this._jsOptions.rawType === "json") { - if (!this._jsOptions.runtimeTypecheck) { - this.emitLine("return JSON.stringify(value);"); + this.emitBlock( + [this.serializerFunctionLine(t, name), " "], + "", + () => { + if (this._jsOptions.rawType === "json") { + if (!this._jsOptions.runtimeTypecheck) { + this.emitLine("return JSON.stringify(value);"); + } else { + this.emitLine( + "return JSON.stringify(uncast(value, ", + typeMap, + "), null, 2);", + ); + } } else { - this.emitLine("return JSON.stringify(uncast(value, ", typeMap, "), null, 2);"); + if (!this._jsOptions.runtimeTypecheck) { + this.emitLine("return value;"); + } else { + this.emitLine( + "return uncast(value, ", + typeMap, + ");", + ); + } } - } else { - if (!this._jsOptions.runtimeTypecheck) { - this.emitLine("return value;"); - } else { - this.emitLine("return uncast(value, ", typeMap, ");"); - } - } - }); + }, + ); }; switch (this._jsOptions.converters) { @@ -264,11 +313,10 @@ export class JavaScriptRenderer extends ConvenienceRenderer { anyMap: anyMapAnnotation, string: stringAnnotation, stringArray: stringArrayAnnotation, - never: neverAnnotation + never: neverAnnotation, } = this.typeAnnotations; this.ensureBlankLine(); - this - .emitMultiline(`function invalidValue(typ${anyAnnotation}, val${anyAnnotation}, key${anyAnnotation}, parent${anyAnnotation} = '')${neverAnnotation} { + this.emitMultiline(`function invalidValue(typ${anyAnnotation}, val${anyAnnotation}, key${anyAnnotation}, parent${anyAnnotation} = '')${neverAnnotation} { const prettyTyp = prettyTypeName(typ); const parentText = parent ? \` on \${parent}\` : ''; const keyText = key ? \` for key "\${key}"\` : ''; @@ -431,11 +479,11 @@ function r(name${stringAnnotation}) { 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`, ); } @@ -443,7 +491,9 @@ function r(name${stringAnnotation}) { if (moduleLine === undefined) { this.emitConvertModuleBody(); } else { - this.emitBlock([moduleLine, " "], "", () => this.emitConvertModuleBody()); + this.emitBlock([moduleLine, " "], "", () => + this.emitConvertModuleBody(), + ); } } @@ -463,12 +513,22 @@ function r(name${stringAnnotation}) { this.emitLine("//"); this.forEachTopLevel("none", (_t, name) => { const camelCaseName = modifySource(camelCase, name); - this.emitLine("// const ", camelCaseName, " = Convert.to", name, "(json);"); + this.emitLine( + "// const ", + camelCaseName, + " = Convert.to", + name, + "(json);", + ); }); if (this._jsOptions.runtimeTypecheck) { this.emitLine("//"); - this.emitLine("// These functions will throw an error if the JSON doesn't"); - this.emitLine("// match the expected interface, even if the JSON is valid."); + this.emitLine( + "// These functions will throw an error if the JSON doesn't", + ); + this.emitLine( + "// match the expected interface, even if the JSON is valid.", + ); } } diff --git a/packages/quicktype-core/src/language/JavaScript/index.ts b/packages/quicktype-core/src/language/JavaScript/index.ts index 12526b3d..aedefb9a 100644 --- a/packages/quicktype-core/src/language/JavaScript/index.ts +++ b/packages/quicktype-core/src/language/JavaScript/index.ts @@ -1,2 +1,5 @@ export { JavaScriptTargetLanguage, javaScriptOptions } from "./language"; -export { JavaScriptRenderer, type JavaScriptTypeAnnotations } from "./JavaScriptRenderer"; +export { + JavaScriptRenderer, + type JavaScriptTypeAnnotations, +} from "./JavaScriptRenderer"; diff --git a/packages/quicktype-core/src/language/JavaScript/language.ts b/packages/quicktype-core/src/language/JavaScript/language.ts index 61d1d93e..33690bbc 100644 --- a/packages/quicktype-core/src/language/JavaScript/language.ts +++ b/packages/quicktype-core/src/language/JavaScript/language.ts @@ -1,22 +1,33 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + 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 "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } 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), + 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" + "secondary", ), converters: convertersOption(), rawType: new EnumOption( @@ -24,20 +35,22 @@ export const javaScriptOptions = { "Type of raw input (json by default)", { json: "json", - any: "any" + any: "any", } as const, "json", - "secondary" - ) + "secondary", + ), }; export const javaScriptLanguageConfig = { displayName: "JavaScript", names: ["javascript", "js", "jsx"], - extension: "js" + extension: "js", } as const; -export class JavaScriptTargetLanguage extends TargetLanguage { +export class JavaScriptTargetLanguage extends TargetLanguage< + typeof javaScriptLanguageConfig +> { public constructor() { super(javaScriptLanguageConfig); } @@ -47,7 +60,8 @@ export class JavaScriptTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); mapping.set("date-time", dateTimeType); @@ -62,7 +76,14 @@ export class JavaScriptTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): JavaScriptRenderer { + return new JavaScriptRenderer( + this, + renderContext, + getOptionValues(javaScriptOptions, untypedOptionValues), + ); } } diff --git a/packages/quicktype-core/src/language/JavaScript/unicodeMaps.ts b/packages/quicktype-core/src/language/JavaScript/unicodeMaps.ts index 0e75bbfa..fde130b6 100644 --- a/packages/quicktype-core/src/language/JavaScript/unicodeMaps.ts +++ b/packages/quicktype-core/src/language/JavaScript/unicodeMaps.ts @@ -30,7 +30,7 @@ function lookupInUnicodeMap(code: number, map: readonly number[]): boolean { return false; } -const enum CharacterCodes { +enum CharacterCodes { maxAsciiCharacter = 0x7f, _ = 0x5f, @@ -43,7 +43,7 @@ const enum CharacterCodes { z = 0x7a, A = 0x41, - Z = 0x5a + Z = 0x5a, } export function isES3IdentifierStart(ch: number): boolean { @@ -52,7 +52,8 @@ export function isES3IdentifierStart(ch: number): boolean { (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || ch === CharacterCodes.$ || ch === CharacterCodes._ || - (ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierStart)) + (ch > CharacterCodes.maxAsciiCharacter && + lookupInUnicodeMap(ch, unicodeES3IdentifierStart)) ); } @@ -63,7 +64,8 @@ export function isES3IdentifierPart(ch: number): boolean { (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) || ch === CharacterCodes.$ || ch === CharacterCodes._ || - (ch > CharacterCodes.maxAsciiCharacter && lookupInUnicodeMap(ch, unicodeES3IdentifierPart)) + (ch > CharacterCodes.maxAsciiCharacter && + lookupInUnicodeMap(ch, unicodeES3IdentifierPart)) ); } @@ -87,71 +89,106 @@ export function isES3IdentifierPart(ch: number): boolean { http://www.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.txt */ const unicodeES3IdentifierStart = [ - 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, - 740, 750, 750, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1164, - 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, - 1569, 1594, 1600, 1610, 1649, 1747, 1749, 1749, 1765, 1766, 1786, 1788, 1808, 1808, 1810, 1836, 1920, 1957, 2309, - 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, - 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, - 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, - 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2784, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, - 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, - 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3168, - 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3294, 3294, 3296, 3297, 3333, 3340, 3342, 3344, - 3346, 3368, 3370, 3385, 3424, 3425, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, - 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, - 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, 3840, - 3840, 3904, 3911, 3913, 3946, 3976, 3979, 4096, 4129, 4131, 4135, 4137, 4138, 4176, 4181, 4256, 4293, 4304, 4342, - 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, - 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, - 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 5024, - 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6067, 6176, 6263, 6272, 6312, 7680, 7835, 7840, 7929, - 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, - 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, - 8319, 8319, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, - 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12346, 12353, 12436, - 12445, 12446, 12449, 12538, 12540, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, - 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 + 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, + 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 890, 890, 902, 902, + 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, + 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, + 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1610, + 1649, 1747, 1749, 1749, 1765, 1766, 1786, 1788, 1808, 1808, 1810, 1836, + 1920, 1957, 2309, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2437, 2444, + 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2524, 2525, + 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, + 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, + 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, + 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2784, 2821, 2828, 2831, 2832, + 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2877, 2877, 2908, 2909, + 2911, 2913, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, + 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3077, 3084, + 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3168, 3169, 3205, 3212, + 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3294, 3294, 3296, 3297, + 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3424, 3425, 3461, 3478, + 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, + 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, + 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, + 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, + 3840, 3840, 3904, 3911, 3913, 3946, 3976, 3979, 4096, 4129, 4131, 4135, + 4137, 4138, 4176, 4181, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, + 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, + 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, + 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, + 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, + 4896, 4934, 4936, 4954, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, + 5792, 5866, 6016, 6067, 6176, 6263, 6272, 6312, 7680, 7835, 7840, 7929, + 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, + 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, + 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, + 8182, 8188, 8319, 8319, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, + 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, + 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12329, 12337, 12341, 12344, + 12346, 12353, 12436, 12445, 12446, 12449, 12538, 12540, 12542, 12549, 12588, + 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 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, ]; 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, - 740, 750, 750, 768, 846, 864, 866, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, - 1024, 1153, 1155, 1158, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, - 1415, 1425, 1441, 1443, 1465, 1467, 1469, 1471, 1471, 1473, 1474, 1476, 1476, 1488, 1514, 1520, 1522, 1569, 1594, - 1600, 1621, 1632, 1641, 1648, 1747, 1749, 1756, 1759, 1768, 1770, 1773, 1776, 1788, 1808, 1836, 1840, 1866, 1920, - 1968, 2305, 2307, 2309, 2361, 2364, 2381, 2384, 2388, 2392, 2403, 2406, 2415, 2433, 2435, 2437, 2444, 2447, 2448, - 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2492, 2494, 2500, 2503, 2504, 2507, 2509, 2519, 2519, 2524, - 2525, 2527, 2531, 2534, 2545, 2562, 2562, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, - 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2649, 2652, 2654, 2654, 2662, 2676, 2689, 2691, 2693, - 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, - 2768, 2768, 2784, 2784, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, - 2873, 2876, 2883, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2913, 2918, 2927, 2946, 2947, 2949, 2954, - 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3006, - 3010, 3014, 3016, 3018, 3021, 3031, 3031, 3047, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, - 3125, 3129, 3134, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3168, 3169, 3174, 3183, 3202, 3203, 3205, 3212, 3214, - 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3262, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3297, - 3302, 3311, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3390, 3395, 3398, 3400, 3402, 3405, 3415, - 3415, 3424, 3425, 3430, 3439, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, - 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, - 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, - 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3805, 3840, 3840, 3864, 3865, 3872, 3881, 3893, - 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3946, 3953, 3972, 3974, 3979, 3984, 3991, 3993, 4028, 4038, 4038, - 4096, 4129, 4131, 4135, 4137, 4138, 4140, 4146, 4150, 4153, 4160, 4169, 4176, 4185, 4256, 4293, 4304, 4342, 4352, - 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, - 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, - 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 4969, 4977, - 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6099, 6112, 6121, 6160, 6169, 6176, 6263, 6272, - 6313, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, - 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, - 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8319, 8319, 8400, 8412, 8417, 8417, 8450, 8450, 8455, 8455, 8458, 8467, - 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, - 12295, 12321, 12335, 12337, 12341, 12344, 12346, 12353, 12436, 12441, 12442, 12445, 12446, 12449, 12542, 12549, - 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, - 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 + 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, + 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 768, 846, 864, 866, + 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, + 1011, 1024, 1153, 1155, 1158, 1164, 1220, 1223, 1224, 1227, 1228, 1232, + 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1441, 1443, + 1465, 1467, 1469, 1471, 1471, 1473, 1474, 1476, 1476, 1488, 1514, 1520, + 1522, 1569, 1594, 1600, 1621, 1632, 1641, 1648, 1747, 1749, 1756, 1759, + 1768, 1770, 1773, 1776, 1788, 1808, 1836, 1840, 1866, 1920, 1968, 2305, + 2307, 2309, 2361, 2364, 2381, 2384, 2388, 2392, 2403, 2406, 2415, 2433, + 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, + 2489, 2492, 2492, 2494, 2500, 2503, 2504, 2507, 2509, 2519, 2519, 2524, + 2525, 2527, 2531, 2534, 2545, 2562, 2562, 2565, 2570, 2575, 2576, 2579, + 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, + 2626, 2631, 2632, 2635, 2637, 2649, 2652, 2654, 2654, 2662, 2676, 2689, + 2691, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, + 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, + 2784, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, + 2864, 2866, 2867, 2870, 2873, 2876, 2883, 2887, 2888, 2891, 2893, 2902, + 2903, 2908, 2909, 2911, 2913, 2918, 2927, 2946, 2947, 2949, 2954, 2958, + 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, + 2986, 2990, 2997, 2999, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3031, + 3031, 3047, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, + 3123, 3125, 3129, 3134, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3168, + 3169, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, + 3251, 3253, 3257, 3262, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, + 3294, 3296, 3297, 3302, 3311, 3330, 3331, 3333, 3340, 3342, 3344, 3346, + 3368, 3370, 3385, 3390, 3395, 3398, 3400, 3402, 3405, 3415, 3415, 3424, + 3425, 3430, 3439, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, + 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, + 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, + 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, + 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, + 3782, 3784, 3789, 3792, 3801, 3804, 3805, 3840, 3840, 3864, 3865, 3872, + 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3946, 3953, + 3972, 3974, 3979, 3984, 3991, 3993, 4028, 4038, 4038, 4096, 4129, 4131, + 4135, 4137, 4138, 4140, 4146, 4150, 4153, 4160, 4169, 4176, 4185, 4256, + 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, + 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, + 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, + 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, + 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 4969, + 4977, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, + 6099, 6112, 6121, 6160, 6169, 6176, 6263, 6272, 6313, 7680, 7835, 7840, + 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, + 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, + 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, + 8180, 8182, 8188, 8255, 8256, 8319, 8319, 8400, 8412, 8417, 8417, 8450, + 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, + 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, + 12295, 12321, 12335, 12337, 12341, 12344, 12346, 12353, 12436, 12441, 12442, + 12445, 12446, 12449, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, + 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 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, ]; diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts index a84f9626..7bd6d68d 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes/JavaScriptPropTypesRenderer.ts @@ -2,9 +2,9 @@ import { arrayIntercalate } from "collection-utils"; 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 type { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; +import type { Sourcelike } from "../../Source"; import { acronymStyle } from "../../support/Acronyms"; import { allLowerWordStyle, @@ -12,31 +12,36 @@ import { combineWords, firstUpperWordStyle, splitIntoWords, - utf16StringEscape + utf16StringEscape, } from "../../support/Strings"; import { panic } from "../../support/Support"; -import { type TargetLanguage } from "../../TargetLanguage"; +import type { TargetLanguage } from "../../TargetLanguage"; import { type ArrayType, type ClassProperty, type ClassType, type ObjectType, PrimitiveType, - type Type + type Type, } from "../../Type"; -import { directlyReachableSingleNamedType, matchType } from "../../Type/TypeUtils"; +import { + directlyReachableSingleNamedType, + matchType, +} from "../../Type/TypeUtils"; import { isES3IdentifierStart } from "../JavaScript/unicodeMaps"; import { legalizeName } from "../JavaScript/utils"; -import { type javaScriptPropTypesOptions } from "./language"; +import type { javaScriptPropTypesOptions } from "./language"; -const identityNamingFunction = funPrefixNamer("properties", s => s); +const identityNamingFunction = funPrefixNamer("properties", (s) => s); export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _jsOptions: OptionValues + private readonly _jsOptions: OptionValues< + typeof javaScriptPropTypesOptions + >, ) { super(targetLanguage, renderContext); } @@ -52,12 +57,12 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isES3IdentifierStart + isES3IdentifierStart, ); } protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("types", s => this.nameStyle(s, true)); + return funPrefixNamer("types", (s) => this.nameStyle(s, true)); } protected namerForObjectProperty(): Namer { @@ -69,7 +74,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); + return funPrefixNamer("enum-cases", (s) => this.nameStyle(s, false)); } protected namedTypeToNameForTopLevel(type: Type): Type | undefined { @@ -81,7 +86,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { 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); @@ -94,25 +99,33 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { const match = matchType( t, - _anyType => "PropTypes.any", - _nullType => "PropTypes.any", - _boolType => "PropTypes.bool", - _integerType => "PropTypes.number", - _doubleType => "PropTypes.number", - _stringType => "PropTypes.string", - arrayType => ["PropTypes.arrayOf(", this.typeMapTypeFor(arrayType.items, false), ")"], - _classType => panic("Should already be handled."), - _mapType => "PropTypes.object", - _enumType => panic("Should already be handled."), - unionType => { - const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false) + (_anyType) => "PropTypes.any", + (_nullType) => "PropTypes.any", + (_boolType) => "PropTypes.bool", + (_integerType) => "PropTypes.number", + (_doubleType) => "PropTypes.number", + (_stringType) => "PropTypes.string", + (arrayType) => [ + "PropTypes.arrayOf(", + this.typeMapTypeFor(arrayType.items, false), + ")", + ], + (_classType) => panic("Should already be handled."), + (_mapType) => "PropTypes.object", + (_enumType) => panic("Should already be handled."), + (unionType) => { + const children = Array.from(unionType.getChildren()).map( + (type: Type) => this.typeMapTypeFor(type, false), ); - return ["PropTypes.oneOfType([", ...arrayIntercalate(", ", children), "])"]; + return [ + "PropTypes.oneOfType([", + ...arrayIntercalate(", ", children), + "])", + ]; }, - _transformedStringType => { + (_transformedStringType) => { return "PropTypes.string"; - } + }, ); if (required) { @@ -126,12 +139,15 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { 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 { - return ["const ", lhs, " = require(", moduleName, ");"]; } + + return ["const ", lhs, " = require(", moduleName, ");"]; } protected emitUsageComments(): void { @@ -148,13 +164,17 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { "", "MyComponent.propTypes = {", " input: MyShape", - "};" + "};", ], - { lineStart: "// " } + { lineStart: "// " }, ); } - protected emitBlock(source: Sourcelike, end: Sourcelike, emit: () => void): void { + protected emitBlock( + source: Sourcelike, + end: Sourcelike, + emit: () => void, + ): void { this.emitLine(source, "{"); this.indent(emit); this.emitLine("}", end); @@ -169,7 +189,13 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { if (this._jsOptions.moduleSystem) { this.emitLine("export const ", name, " = ", value, ";"); } else { - this.emitLine("module.exports = exports = { ", name, ": ", value, " };"); + this.emitLine( + "module.exports = exports = { ", + name, + ": ", + value, + " };", + ); } } @@ -182,15 +208,25 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { this.forEachEnum("none", (enumType, enumName) => { const options: Sourcelike = []; - this.forEachEnumCase(enumType, "none", (name: Name, _jsonName, _position) => { - options.push("'"); - options.push(name); - options.push("'"); - options.push(", "); - }); + this.forEachEnumCase( + enumType, + "none", + (name: Name, _jsonName, _position) => { + options.push("'"); + options.push(name); + options.push("'"); + options.push(", "); + }, + ); options.pop(); - this.emitLine(["const _", enumName, " = PropTypes.oneOfType([", ...options, "]);"]); + this.emitLine([ + "const _", + enumName, + " = PropTypes.oneOfType([", + ...options, + "]);", + ]); }); const order: number[] = []; @@ -208,14 +244,14 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { // pull out all names const source = mapValue[index]; - const names = source.filter(value => value as Name); + const names = source.filter((value) => value as Name); // must be behind all these names - names.forEach(name => { + names.forEach((name) => { const depName = name; // find this name's ordinal, if it has already been added - order.forEach(orderItem => { + order.forEach((orderItem) => { const depIndex = orderItem; if (mapKey[depIndex] === depName) { // this is the index of the dependency, so make sure we come after it @@ -229,7 +265,7 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { }); // now emit ordered source - order.forEach(i => this.emitGatheredSource(mapValue[i])); + order.forEach((i) => this.emitGatheredSource(mapValue[i])); // now emit top levels this.forEachTopLevel("none", (type, name) => { @@ -239,7 +275,11 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { } else { if (type.kind === "array") { this.ensureBlankLine(); - this.emitExport(name, ["PropTypes.arrayOf(", this.typeMapTypeFor((type as ArrayType).items), ")"]); + this.emitExport(name, [ + "PropTypes.arrayOf(", + this.typeMapTypeFor((type as ArrayType).items), + ")", + ]); } else { this.ensureBlankLine(); this.emitExport(name, ["_", name]); @@ -253,7 +293,12 @@ export class JavaScriptPropTypesRenderer extends ConvenienceRenderer { this.emitLine("_", name, " = PropTypes.shape({"); this.indent(() => { this.forEachClassProperty(t, "none", (_, jsonName, property) => { - this.emitLine(`"${utf16StringEscape(jsonName)}"`, ": ", this.typeMapTypeForProperty(property), ","); + this.emitLine( + `"${utf16StringEscape(jsonName)}"`, + ": ", + this.typeMapTypeForProperty(property), + ",", + ); }); }); this.emitLine("});"); diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts index 273e8187..f17587d2 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes/index.ts @@ -1,2 +1,5 @@ -export { JavaScriptPropTypesTargetLanguage, javaScriptPropTypesOptions } from "./language"; +export { + JavaScriptPropTypesTargetLanguage, + javaScriptPropTypesOptions, +} from "./language"; export { JavaScriptPropTypesRenderer } from "./JavaScriptPropTypesRenderer"; diff --git a/packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts b/packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts index 317ac859..9c9cb1ec 100644 --- a/packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts +++ b/packages/quicktype-core/src/language/JavaScriptPropTypes/language.ts @@ -1,9 +1,9 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { EnumOption, getOptionValues } from "../../RendererOptions"; import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; import { convertersOption } from "../../support/Converters"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { JavaScriptPropTypesRenderer } from "./JavaScriptPropTypesRenderer"; @@ -15,19 +15,21 @@ export const javaScriptPropTypesOptions = { "Which module system to use", { "common-js": false, - "es6": true + es6: true, } as const, - "es6" - ) + "es6", + ), }; export const javaScriptPropTypesLanguageConfig = { displayName: "JavaScript PropTypes", names: ["javascript-prop-types"], - extension: "js" + extension: "js", } as const; -export class JavaScriptPropTypesTargetLanguage extends TargetLanguage { +export class JavaScriptPropTypesTargetLanguage extends TargetLanguage< + typeof javaScriptPropTypesLanguageConfig +> { public constructor() { super(javaScriptPropTypesLanguageConfig); } @@ -36,14 +38,14 @@ export class JavaScriptPropTypesTargetLanguage extends TargetLanguage( renderContext: RenderContext, - untypedOptionValues: FixMeOptionsType + untypedOptionValues: RendererOptions, ): JavaScriptPropTypesRenderer { return new JavaScriptPropTypesRenderer( this, renderContext, - getOptionValues(javaScriptPropTypesOptions, untypedOptionValues) + getOptionValues(javaScriptPropTypesOptions, untypedOptionValues), ); } } diff --git a/packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts b/packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts index 0207fd67..3401ed1f 100644 --- a/packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts +++ b/packages/quicktype-core/src/language/Kotlin/KotlinJacksonRenderer.ts @@ -1,12 +1,12 @@ import { arrayIntercalate, iterableSome } from "collection-utils"; -import { type Name } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { type OptionValues } from "../../RendererOptions"; +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 { TargetLanguage } from "../../TargetLanguage"; import { type ArrayType, ClassType, @@ -14,19 +14,19 @@ import { type MapType, type PrimitiveType, type Type, - UnionType + UnionType, } from "../../Type"; import { matchType, nullableFromUnion } from "../../Type/TypeUtils"; import { KotlinRenderer } from "./KotlinRenderer"; -import { type kotlinOptions } from "./language"; +import type { kotlinOptions } from "./language"; import { stringEscape } from "./utils"; export class KotlinJacksonRenderer extends KotlinRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues + _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext, _kotlinOptions); } @@ -34,29 +34,37 @@ export class KotlinJacksonRenderer extends KotlinRenderer { 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", + (_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", + (_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() + (_enumType) => "is TextNode", + (_unionType) => mustNotHappen(), ); } protected emitUsageHeader(): void { - this.emitLine("// To parse the JSON, install jackson-module-kotlin and do:"); + 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)"); + this.emitLine( + "// val ", + modifySource(camelCase, name), + " = ", + name, + ".fromJson(jsonString)", + ); }); } @@ -74,17 +82,17 @@ 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(); } - let converters: Sourcelike[][] = []; + const converters: Sourcelike[][] = []; // if (hasEmptyObjects) { // converters.push([["convert(JsonNode::class,"], [" { it },"], [" { writeValueAsString(it) })"]]); // } @@ -92,22 +100,26 @@ 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)"], ]); }); this.ensureBlankLine(); this.emitLine("val mapper = jacksonObjectMapper().apply {"); this.indent(() => { - this.emitLine("propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE"); - this.emitLine("setSerializationInclusion(JsonInclude.Include.NON_NULL)"); + this.emitLine( + "propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE", + ); + this.emitLine( + "setSerializationInclusion(JsonInclude.Include.NON_NULL)", + ); }); if (converters.length > 0) { @@ -120,14 +132,26 @@ import com.fasterxml.jackson.module.kotlin.*`); protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitBlock( - ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], + [ + "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)"); + this.emitLine( + "fun fromJson(json: String) = mapper.readValue<", + name, + ">(json)", + ); }); - } + }, ); } @@ -141,15 +165,19 @@ import com.fasterxml.jackson.module.kotlin.*`); elementType, ">) : HashMap(elements)" + ">(elements)", ], () => { this.emitLine("fun toJson() = mapper.writeValueAsString(this)"); this.ensureBlankLine(); this.emitBlock("companion object", () => { - this.emitLine("fun fromJson(json: String) = mapper.readValue<", name, ">(json)"); + this.emitLine( + "fun fromJson(json: String) = mapper.readValue<", + name, + ">(json)", + ); }); - } + }, ); } @@ -157,7 +185,7 @@ import com.fasterxml.jackson.module.kotlin.*`); propName: Name, jsonName: string, required: boolean, - ignore = false + ignore = false, ): Sourcelike | undefined { const escapedName = stringEscape(jsonName); const namesDiffer = this.sourcelikeToString(propName) !== escapedName; @@ -166,7 +194,7 @@ import com.fasterxml.jackson.module.kotlin.*`); const propertyOpts: Sourcelike[] = []; if (namesDiffer || isPrefixBool) { - propertyOpts.push('"' + escapedName + '"'); + propertyOpts.push(`"${escapedName}"`); } if (required) { @@ -174,8 +202,16 @@ import com.fasterxml.jackson.module.kotlin.*`); } if (propertyOpts.length > 0) { - properties.push(["@get:JsonProperty(", arrayIntercalate(", ", propertyOpts), ")"]); - properties.push(["@field:JsonProperty(", arrayIntercalate(", ", propertyOpts), ")"]); + properties.push([ + "@get:JsonProperty(", + arrayIntercalate(", ", propertyOpts), + ")", + ]); + properties.push([ + "@field:JsonProperty(", + arrayIntercalate(", ", propertyOpts), + ")", + ]); } if (ignore) { @@ -193,13 +229,20 @@ import com.fasterxml.jackson.module.kotlin.*`); } protected emitClassDefinitionMethods(c: ClassType, className: Name): void { - const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); + 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)"); + this.emitLine( + "fun fromJson(json: String) = mapper.readValue<", + className, + ">(json)", + ); }); }); } else { @@ -207,7 +250,12 @@ import com.fasterxml.jackson.module.kotlin.*`); } } - protected renameAttribute(name: Name, jsonName: string, required: boolean, meta: Array<() => void>): 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)); @@ -220,18 +268,35 @@ import com.fasterxml.jackson.module.kotlin.*`); 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.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); - }); + this.emitBlock( + [ + "fun fromValue(value: String): ", + enumName, + " = when (value)", + ], + () => { + const table: Sourcelike[][] = []; + this.forEachEnumCase(e, "none", (name, json) => { + table.push([ + [`"${stringEscape(json)}"`], + [" -> ", name], + ]); + }); + table.push([ + ["else"], + [" -> throw IllegalArgumentException()"], + ]); + this.emitTable(table); + }, + ); }); }); } @@ -254,13 +319,15 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso u: UnionType, nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, - unionName: Name + unionName: Name, ): void { this.ensureBlankLine(); - this.emitLine("fun toJson(): String = mapper.writeValueAsString(when (this) {"); + this.emitLine( + "fun toJson(): String = mapper.writeValueAsString(when (this) {", + ); this.indent(() => { - let toJsonTable: Sourcelike[][] = []; - this.forEachUnionMember(u, nonNulls, "none", null, name => { + const toJsonTable: Sourcelike[][] = []; + this.forEachUnionMember(u, nonNulls, "none", null, (name) => { toJsonTable.push([["is ", name], [" -> this.value"]]); }); if (maybeNull !== null) { @@ -273,18 +340,37 @@ private fun ObjectMapper.convert(k: kotlin.reflect.KClass<*>, fromJson: (Jso this.emitLine("})"); this.ensureBlankLine(); this.emitBlock("companion object", () => { - this.emitLine("fun fromJson(jn: JsonNode): ", unionName, " = when (jn) {"); + 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))"]]); - }); + const 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([ + [this.unionMemberJsonValueGuard(maybeNull, "jn")], + [" -> ", name, "()"], + ]); } - table.push([["else"], [" -> throw IllegalArgumentException()"]]); + 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 index d5dadf8c..e0dbbf25 100644 --- a/packages/quicktype-core/src/language/Kotlin/KotlinKlaxonRenderer.ts +++ b/packages/quicktype-core/src/language/Kotlin/KotlinKlaxonRenderer.ts @@ -1,12 +1,12 @@ import { arrayIntercalate, iterableSome } from "collection-utils"; -import { type Name } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { type OptionValues } from "../../RendererOptions"; +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 { TargetLanguage } from "../../TargetLanguage"; import { type ArrayType, ClassType, @@ -14,19 +14,19 @@ import { type MapType, type PrimitiveType, type Type, - UnionType + UnionType, } from "../../Type"; import { matchType, nullableFromUnion } from "../../Type/TypeUtils"; import { KotlinRenderer } from "./KotlinRenderer"; -import { type kotlinOptions } from "./language"; +import type { kotlinOptions } from "./language"; import { stringEscape } from "./utils"; export class KotlinKlaxonRenderer extends KotlinRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues + _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext, _kotlinOptions); } @@ -34,38 +34,58 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { 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() + (_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<*>", + (_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", + (_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() + (_enumType) => "is String", + (_unionType) => mustNotHappen(), ); } @@ -73,7 +93,13 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { 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)"); + this.emitLine( + "// val ", + modifySource(camelCase, name), + " = ", + name, + ".fromJson(jsonString)", + ); }); } @@ -84,33 +110,37 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { 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(); } - let converters: Sourcelike[][] = []; + const converters: Sourcelike[][] = []; if (hasEmptyObjects) { - converters.push([[".convert(JsonObject::class,"], [" { it.obj!! },"], [" { it.toJsonString() })"]]); + 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)"], ]); }); @@ -124,9 +154,19 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { protected emitTopLevelArray(t: ArrayType, name: Name): void { const elementType = this.kotlinType(t.items); this.emitBlock( - ["class ", name, "(elements: Collection<", elementType, ">) : ArrayList<", elementType, ">(elements)"], + [ + "class ", + name, + "(elements: Collection<", + elementType, + ">) : ArrayList<", + elementType, + ">(elements)", + ], () => { - this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); + this.emitLine( + "public fun toJson() = klaxon.toJsonString(this)", + ); this.ensureBlankLine(); this.emitBlock("companion object", () => { this.emitLine( @@ -134,10 +174,10 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { name, "(klaxon.parseArray<", elementType, - ">(json)!!)" + ">(json)!!)", ); }); - } + }, ); } @@ -151,10 +191,12 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { elementType, ">) : HashMap(elements)" + ">(elements)", ], () => { - this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); + this.emitLine( + "public fun toJson() = klaxon.toJsonString(this)", + ); this.ensureBlankLine(); this.emitBlock("companion object", () => { this.emitBlock( @@ -163,17 +205,21 @@ 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[] = []; @@ -185,7 +231,9 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { properties.push("ignored = true"); } - return properties.length === 0 ? undefined : ["@Json(", arrayIntercalate(", ", properties), ")"]; + return properties.length === 0 + ? undefined + : ["@Json(", arrayIntercalate(", ", properties), ")"]; } protected emitEmptyClassDefinition(c: ClassType, className: Name): void { @@ -195,13 +243,22 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } protected emitClassDefinitionMethods(c: ClassType, className: Name): void { - const isTopLevel = iterableSome(this.topLevels, ([_, top]) => top === c); + const isTopLevel = iterableSome( + this.topLevels, + ([_, top]) => top === c, + ); if (isTopLevel) { this.emitBlock(")", () => { - this.emitLine("public fun toJson() = klaxon.toJsonString(this)"); + 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)"); + this.emitLine( + "public fun fromJson(json: String) = klaxon.parse<", + className, + ">(json)", + ); }); }); } else { @@ -209,7 +266,12 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { } } - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): 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)); @@ -222,18 +284,35 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { 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.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); - }); + this.emitBlock( + [ + "public fun fromValue(value: String): ", + enumName, + " = when (value)", + ], + () => { + const table: Sourcelike[][] = []; + this.forEachEnumCase(e, "none", (name, json) => { + table.push([ + [`"${stringEscape(json)}"`], + [" -> ", name], + ]); + }); + table.push([ + ["else"], + [" -> throw IllegalArgumentException()"], + ]); + this.emitTable(table); + }, + ); }); }); } @@ -241,19 +320,25 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { 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.emitTable([ - ["override fun toJson(value: Any)", " = toJson(value as T)"], - ["override fun fromJson(jv: JsonValue)", " = fromJson(jv) as Any"], + [ + "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("})"); @@ -264,13 +349,15 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { u: UnionType, nonNulls: ReadonlySet, maybeNull: PrimitiveType | null, - unionName: Name + unionName: Name, ): void { this.ensureBlankLine(); - this.emitLine("public fun toJson(): String = klaxon.toJsonString(when (this) {"); + this.emitLine( + "public fun toJson(): String = klaxon.toJsonString(when (this) {", + ); this.indent(() => { - let toJsonTable: Sourcelike[][] = []; - this.forEachUnionMember(u, nonNulls, "none", null, name => { + const toJsonTable: Sourcelike[][] = []; + this.forEachUnionMember(u, nonNulls, "none", null, (name) => { toJsonTable.push([["is ", name], [" -> this.value"]]); }); if (maybeNull !== null) { @@ -283,21 +370,48 @@ export class KotlinKlaxonRenderer extends KotlinRenderer { this.emitLine("})"); this.ensureBlankLine(); this.emitBlock("companion object", () => { - this.emitLine("public fun fromJson(jv: JsonValue): ", unionName, " = when (jv.inside) {"); + 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"), "!!)"] - ]); - }); + const 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([ + [ + this.unionMemberJsonValueGuard( + maybeNull, + "jv.inside", + ), + ], + [" -> ", name, "()"], + ]); } - table.push([["else"], [" -> throw IllegalArgumentException()"]]); + 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 index b200677b..5e1c45b6 100644 --- a/packages/quicktype-core/src/language/Kotlin/KotlinRenderer.ts +++ b/packages/quicktype-core/src/language/Kotlin/KotlinRenderer.ts @@ -1,11 +1,17 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } 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 OptionValues } from "../../RendererOptions"; +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 type { TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, @@ -15,19 +21,23 @@ import { type ObjectType, type PrimitiveType, type Type, - type UnionType + type UnionType, } from "../../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../Type/TypeUtils"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type kotlinOptions } from "./language"; +import type { kotlinOptions } from "./language"; import { kotlinNameStyle } from "./utils"; export class KotlinRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _kotlinOptions: OptionValues + protected readonly _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext); } @@ -36,15 +46,24 @@ export class KotlinRenderer extends ConvenienceRenderer { 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 }; } @@ -53,27 +72,61 @@ export class KotlinRenderer extends ConvenienceRenderer { } protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); + 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))); + return funPrefixNamer("lower", (s) => + kotlinNameStyle( + false, + s, + acronymStyle(this._kotlinOptions.acronymStyle), + ), + ); } protected makeUnionMemberNamer(): Namer { - return funPrefixNamer("upper", s => kotlinNameStyle(true, s) + "Value"); + return funPrefixNamer( + "upper", + (s) => `${kotlinNameStyle(true, s)}Value`, + ); } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("upper", s => kotlinNameStyle(true, s, acronymStyle(this._kotlinOptions.acronymStyle))); + return funPrefixNamer("upper", (s) => + kotlinNameStyle( + true, + s, + acronymStyle(this._kotlinOptions.acronymStyle), + ), + ); } protected emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + 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" ? ["(", ")"] : ["{", "})"]; + 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); @@ -85,37 +138,62 @@ export class KotlinRenderer extends ConvenienceRenderer { // (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 { - return ["Map"]; + 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, - _anyType => { - return maybeAnnotated(withIssues, anyTypeIssueAnnotation, this.anySourceType(optional)); + (_anyType) => { + return maybeAnnotated( + withIssues, + anyTypeIssueAnnotation, + this.anySourceType(optional), + ); }, - _nullType => { - return maybeAnnotated(withIssues, nullTypeIssueAnnotation, 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 => { + (_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]; + if (nullable !== null) + return [this.kotlinType(nullable, withIssues), optional]; return this.nameForNamedType(unionType); - } + }, ); } @@ -147,7 +225,13 @@ export class KotlinRenderer extends ConvenienceRenderer { protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.kotlinType(t.values); - this.emitLine(["typealias ", name, " = HashMap"]); + this.emitLine([ + "typealias ", + name, + " = HashMap", + ]); } protected emitEmptyClassDefinition(c: ClassType, className: Name): void { @@ -165,9 +249,9 @@ export class KotlinRenderer extends ConvenienceRenderer { const kotlinType = (p: ClassProperty): Sourcelike => { if (p.isOptional) { return [this.kotlinType(p.type, true, true), "?"]; - } else { - return this.kotlinType(p.type, true); } + + return this.kotlinType(p.type, true); }; this.emitDescription(this.descriptionForType(c)); @@ -177,12 +261,18 @@ export class KotlinRenderer extends ConvenienceRenderer { 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 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 meta: Array<() => void> = []; - const description = this.descriptionForClassProperty(c, jsonName); + const description = this.descriptionForClassProperty( + c, + jsonName, + ); if (description !== undefined) { meta.push(() => this.emitDescription(description)); } @@ -197,7 +287,14 @@ export class KotlinRenderer extends ConvenienceRenderer { emit(); } - this.emitLine("val ", name, ": ", kotlinType(p), nullableOrOptional ? " = null" : "", last ? "" : ","); + this.emitLine( + "val ", + name, + ": ", + kotlinType(p), + nullableOrOptional ? " = null" : "", + last ? "" : ",", + ); if (meta.length > 0 && !last) { this.ensureBlankLine(); @@ -210,7 +307,10 @@ export class KotlinRenderer extends ConvenienceRenderer { this.emitClassDefinitionMethods(c, className); } - protected emitClassDefinitionMethods(_c: ClassType, _className: Name): void { + protected emitClassDefinitionMethods( + _c: ClassType, + _className: Name, + ): void { this.emitLine(")"); } @@ -218,7 +318,12 @@ export class KotlinRenderer extends ConvenienceRenderer { // to be overridden } - protected renameAttribute(_name: Name, _jsonName: string, _required: boolean, _meta: Array<() => void>): void { + protected renameAttribute( + _name: Name, + _jsonName: string, + _required: boolean, + _meta: Array<() => void>, + ): void { // to be overridden } @@ -227,7 +332,7 @@ export class KotlinRenderer extends ConvenienceRenderer { this.emitBlock(["enum class ", enumName], () => { let count = e.cases.size; - this.forEachEnumCase(e, "none", name => { + this.forEachEnumCase(e, "none", (name) => { this.emitLine(name, --count === 0 ? "" : ","); }); }); @@ -237,7 +342,7 @@ export class KotlinRenderer extends ConvenienceRenderer { function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; - return "_" + kind; + return `_${kind}`; } this.emitDescription(this.descriptionForType(u)); @@ -246,17 +351,29 @@ export class KotlinRenderer extends ConvenienceRenderer { 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, "()"] - ]); - }); + const 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, "()"] + [" : ", unionName, "()"], ]); } @@ -271,7 +388,7 @@ export class KotlinRenderer extends ConvenienceRenderer { _u: UnionType, _nonNulls: ReadonlySet, _maybeNull: PrimitiveType | null, - _unionName: Name + _unionName: Name, ): void { // to be overridden } @@ -294,7 +411,7 @@ 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), ); } } diff --git a/packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts b/packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts index 66a579b4..8084f36c 100644 --- a/packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts +++ b/packages/quicktype-core/src/language/Kotlin/KotlinXRenderer.ts @@ -1,13 +1,18 @@ -import { type Name } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { type OptionValues } from "../../RendererOptions"; +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 type { TargetLanguage } from "../../TargetLanguage"; +import type { + ArrayType, + EnumType, + MapType, + Type, +} from "../../Type"; import { KotlinRenderer } from "./KotlinRenderer"; -import { type kotlinOptions } from "./language"; +import type { kotlinOptions } from "./language"; import { stringEscape } from "./utils"; /** @@ -18,7 +23,7 @@ export class KotlinXRenderer extends KotlinRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - _kotlinOptions: OptionValues + _kotlinOptions: OptionValues, ) { super(targetLanguage, renderContext, _kotlinOptions); } @@ -27,7 +32,11 @@ export class KotlinXRenderer extends KotlinRenderer { 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") { @@ -37,7 +46,11 @@ 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") { @@ -62,15 +75,21 @@ export class KotlinXRenderer extends KotlinRenderer { } protected emitUsageHeader(): void { - this.emitLine("// To parse the JSON, install kotlin's serialization plugin and do:"); + 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 }"]); + table.push([ + "// val ", + "json", + " = Json { allowStructuredMapKeys = true }", + ]); this.forEachTopLevel("none", (_, name) => { table.push([ "// val ", modifySource(camelCase, name), - ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)` + ` = json.parse(${this.sourcelikeToString(name)}.serializer(), jsonString)`, ]); }); this.emitTable(table); @@ -89,7 +108,12 @@ export class KotlinXRenderer extends KotlinRenderer { this.emitLine("@Serializable"); } - protected renameAttribute(name: Name, jsonName: string, _required: boolean, meta: Array<() => void>): 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)); @@ -114,7 +138,12 @@ export class KotlinXRenderer extends KotlinRenderer { let count = e.cases.size; this.forEachEnumCase(e, "none", (name, json) => { const jsonEnum = stringEscape(json); - this.emitLine(`@SerialName("${jsonEnum}") `, name, `("${jsonEnum}")`, --count === 0 ? ";" : ","); + 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 index 8e83c738..89993e32 100644 --- a/packages/quicktype-core/src/language/Kotlin/constants.ts +++ b/packages/quicktype-core/src/language/Kotlin/constants.ts @@ -47,5 +47,5 @@ export const keywords = [ "JsonObject", "JsonValue", "Converter", - "Klaxon" + "Klaxon", ] as const; diff --git a/packages/quicktype-core/src/language/Kotlin/language.ts b/packages/quicktype-core/src/language/Kotlin/language.ts index 27d149a3..ce72896a 100644 --- a/packages/quicktype-core/src/language/Kotlin/language.ts +++ b/packages/quicktype-core/src/language/Kotlin/language.ts @@ -1,10 +1,14 @@ -import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; -import { type RenderContext } from "../../Renderer"; -import { EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import type { RenderContext } from "../../Renderer"; +import { + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; import { assertNever } from "../../support/Support"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { KotlinJacksonRenderer } from "./KotlinJacksonRenderer"; import { KotlinKlaxonRenderer } from "./KotlinKlaxonRenderer"; @@ -17,23 +21,25 @@ export const kotlinOptions = { "Serialization framework", { "just-types": "None", - "jackson": "Jackson", - "klaxon": "Klaxon", - "kotlinx": "KotlinX" + jackson: "Jackson", + klaxon: "Klaxon", + kotlinx: "KotlinX", } as const, - "klaxon" + "klaxon", ), acronymStyle: acronymOption(AcronymStyleOptions.Pascal), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), }; export const kotlinLanguageConfig = { displayName: "Kotlin", names: ["kotlin"], - extension: "kt" + extension: "kt", } as const; -export class KotlinTargetLanguage extends TargetLanguage { +export class KotlinTargetLanguage extends TargetLanguage< + typeof kotlinLanguageConfig +> { public constructor() { super(kotlinLanguageConfig); } @@ -50,7 +56,10 @@ export class KotlinTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): ConvenienceRenderer { const options = getOptionValues(kotlinOptions, untypedOptionValues); switch (options.framework) { diff --git a/packages/quicktype-core/src/language/Kotlin/utils.ts b/packages/quicktype-core/src/language/Kotlin/utils.ts index 69fc8fb0..d47d933e 100644 --- a/packages/quicktype-core/src/language/Kotlin/utils.ts +++ b/packages/quicktype-core/src/language/Kotlin/utils.ts @@ -11,7 +11,7 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap + utf32ConcatMap, } from "../../support/Strings"; function isPartCharacter(codePoint: number): boolean { @@ -27,7 +27,7 @@ const legalizeName = legalizeCharacters(isPartCharacter); export function kotlinNameStyle( isUpper: boolean, original: string, - acronymsStyle: (s: string) => string = allUpperWordStyle + acronymsStyle: (s: string) => string = allUpperWordStyle, ): string { const words = splitIntoWords(original); return combineWords( @@ -38,7 +38,7 @@ export function kotlinNameStyle( isUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -47,7 +47,9 @@ function unicodeEscape(codePoint: number): string { } // eslint-disable-next-line @typescript-eslint/naming-convention -const _stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); +const _stringEscape = utf32ConcatMap( + escapeNonPrintableMapper(isPrintable, unicodeEscape), +); export 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/Objective-C/ObjectiveCRenderer.ts b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts index e8c24757..5d0917db 100644 --- a/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts +++ b/packages/quicktype-core/src/language/Objective-C/ObjectiveCRenderer.ts @@ -1,25 +1,51 @@ -import { iterableFirst, iterableSome, mapContains, mapFirst, mapSome } from "collection-utils"; +import { + iterableFirst, + iterableSome, + mapContains, + mapFirst, + mapSome, +} from "collection-utils"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +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 { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; import { type Sourcelike, modifySource } from "../../Source"; -import { camelCase, fastIsUpperCase, repeatString, stringEscape } from "../../support/Strings"; +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 "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + ClassType, + EnumType, + MapType, + Type, + UnionType, +} from "../../Type"; +import { + isAnyOrNull, + matchType, + nullableFromUnion, +} from "../../Type/TypeUtils"; import { forbiddenPropertyNames, keywords } from "./constants"; -import { type objectiveCOptions } from "./language"; +import type { objectiveCOptions } from "./language"; import { DEFAULT_CLASS_PREFIX, forbiddenForEnumCases, propertyNameStyle, splitExtension, staticEnumValuesIdentifier, - typeNameStyle + typeNameStyle, } from "./utils"; type MemoryAttribute = "assign" | "strong" | "copy"; @@ -34,7 +60,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); @@ -50,7 +76,10 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { private inferClassPrefix(name: string): string { const l = name.length; let firstNonUpper = 0; - while (firstNonUpper < l && fastIsUpperCase(name.charCodeAt(firstNonUpper))) { + while ( + firstNonUpper < l && + fastIsUpperCase(name.charCodeAt(firstNonUpper)) + ) { firstNonUpper += 1; } @@ -62,27 +91,36 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return keywords; } - protected forbiddenForObjectProperties(_c: ClassType, _className: Name): ForbiddenWordsInfo { - return { names: forbiddenPropertyNames as unknown as string[], includeGlobalForbidden: true }; + protected forbiddenForObjectProperties( + _c: ClassType, + _className: Name, + ): ForbiddenWordsInfo { + return { + names: forbiddenPropertyNames as unknown as string[], + includeGlobalForbidden: true, + }; } - protected forbiddenForEnumCases(_e: EnumType, _enumName: Name): ForbiddenWordsInfo { + protected forbiddenForEnumCases( + _e: EnumType, + _enumName: Name, + ): ForbiddenWordsInfo { return { names: forbiddenForEnumCases, includeGlobalForbidden: true }; } protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("types", rawName => typeNameStyle(this._classPrefix, rawName)); + return funPrefixNamer("types", (rawName) => + typeNameStyle(this._classPrefix, rawName), + ); } 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" - ]); + return new Namer( + "properties", + (s) => propertyNameStyle(s, p.type.kind === "bool"), + ["_", "the", "one", "some", "another"], + ); } protected makeUnionMemberNamer(): null { @@ -122,7 +160,10 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } protected startFile(basename: Sourcelike, extension: string): void { - assert(this._currentFilename === undefined, "Previous file wasn't finished"); + assert( + this._currentFilename === undefined, + "Previous file wasn't finished", + ); // FIXME: The filenames should actually be Sourcelikes, too this._currentFilename = `${this.sourcelikeToString(basename)}.${extension}`; } @@ -135,34 +176,39 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { 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"), - _stringType => "copy", - _arrayType => "copy", - _classType => "strong", - _mapType => "copy", - _enumType => "assign", - unionType => { + (_anyType) => "copy", + (_nullType) => "copy", + (_boolType) => (isNullable ? "strong" : "assign"), + (_integerType) => (isNullable ? "strong" : "assign"), + (_doubleType) => (isNullable ? "strong" : "assign"), + (_stringType) => "copy", + (_arrayType) => "copy", + (_classType) => "strong", + (_mapType) => "copy", + (_enumType) => "assign", + (unionType) => { const nullable = nullableFromUnion(unionType); - return nullable !== null ? this.memoryAttribute(nullable, true) : "copy"; - } + return nullable !== null + ? this.memoryAttribute(nullable, true) + : "copy"; + }, ); } protected objcType(t: Type, nullableOrBoxed = false): [Sourcelike, string] { return matchType<[Sourcelike, string]>( t, - _anyType => ["id", ""], + (_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", ""]), - _stringType => ["NSString", " *"], - arrayType => { + (_nullType) => ["id", ""], + (_boolType) => + nullableOrBoxed ? ["NSNumber", " *"] : ["BOOL", ""], + (_integerType) => + nullableOrBoxed ? ["NSNumber", " *"] : ["NSInteger", ""], + (_doubleType) => + nullableOrBoxed ? ["NSNumber", " *"] : ["double", ""], + (_stringType) => ["NSString", " *"], + (arrayType) => { const itemType = arrayType.items; const itemTypeName = this.objcType(itemType, true); // NSArray* === NSArray* @@ -172,168 +218,307 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { return [["NSArray<", itemTypeName, ">"], " *"]; }, - classType => [this.nameForNamedType(classType), " *"], - mapType => [["NSDictionary"], " *"], - enumType => [this.nameForNamedType(enumType), " *"], - unionType => { + (classType) => [this.nameForNamedType(classType), " *"], + (mapType) => [ + [ + "NSDictionary", + ], + " *", + ], + (enumType) => [this.nameForNamedType(enumType), " *"], + (unionType) => { const nullable = nullableFromUnion(unionType); - return nullable !== null ? this.objcType(nullable, true) : ["id", ""]; - } + return nullable !== null + ? this.objcType(nullable, true) + : ["id", ""]; + }, ); } private jsonType(t: Type): [Sourcelike, string] { return matchType<[Sourcelike, string]>( t, - _anyType => ["id", ""], + (_anyType) => ["id", ""], // For now, we're treating nulls just like any - _nullType => ["id", ""], - _boolType => ["NSNumber", " *"], - _integerType => ["NSNumber", " *"], - _doubleType => ["NSNumber", " *"], - _stringType => ["NSString", " *"], - _arrayType => ["NSArray", " *"], - _classType => ["NSDictionary", " *"], - mapType => [["NSDictionary"], " *"], - _enumType => ["NSString", " *"], - unionType => { + (_nullType) => ["id", ""], + (_boolType) => ["NSNumber", " *"], + (_integerType) => ["NSNumber", " *"], + (_doubleType) => ["NSNumber", " *"], + (_stringType) => ["NSString", " *"], + (_arrayType) => ["NSArray", " *"], + (_classType) => ["NSDictionary", " *"], + (mapType) => [ + [ + "NSDictionary", + ], + " *", + ], + (_enumType) => ["NSString", " *"], + (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, - _nullType => dynamic, - _boolType => dynamic, - _integerType => dynamic, - _doubleType => dynamic, - _stringType => dynamic, - arrayType => ["map(", dynamic, ", λ(id x, ", this.fromDynamicExpression(arrayType.items, "x"), "))"], - classType => ["[", this.nameForNamedType(classType), " fromJSONDictionary:", dynamic, "]"], - mapType => ["map(", dynamic, ", λ(id x, ", this.fromDynamicExpression(mapType.values, "x"), "))"], - enumType => ["[", this.nameForNamedType(enumType), " withValue:", dynamic, "]"], - unionType => { + (_anyType) => dynamic, + (_nullType) => dynamic, + (_boolType) => dynamic, + (_integerType) => dynamic, + (_doubleType) => dynamic, + (_stringType) => dynamic, + (arrayType) => [ + "map(", + dynamic, + ", λ(id x, ", + this.fromDynamicExpression(arrayType.items, "x"), + "))", + ], + (classType) => [ + "[", + this.nameForNamedType(classType), + " fromJSONDictionary:", + dynamic, + "]", + ], + (mapType) => [ + "map(", + dynamic, + ", λ(id x, ", + this.fromDynamicExpression(mapType.values, "x"), + "))", + ], + (enumType) => [ + "[", + this.nameForNamedType(enumType), + " withValue:", + dynamic, + "]", + ], + (unionType) => { const nullable = nullableFromUnion(unionType); - return nullable !== null ? this.fromDynamicExpression(nullable, dynamic) : dynamic; - } + return nullable !== null + ? this.fromDynamicExpression(nullable, dynamic) + : dynamic; + }, ); } protected toDynamicExpression(t: Type, typed: Sourcelike): Sourcelike { return matchType( t, - _anyType => ["NSNullify(", typed, ")"], - _nullType => ["NSNullify(", typed, ")"], + (_anyType) => ["NSNullify(", typed, ")"], + (_nullType) => ["NSNullify(", typed, ")"], // Sadly, KVC - _boolType => [typed, " ? @YES : @NO"], - _integerType => typed, - _doubleType => typed, - _stringType => typed, - arrayType => { + (_boolType) => [typed, " ? @YES : @NO"], + (_integerType) => typed, + (_doubleType) => typed, + (_stringType) => typed, + (arrayType) => { if (this.implicitlyConvertsFromJSON(arrayType)) { // TODO check each value type return typed; } - return ["map(", typed, ", λ(id x, ", this.toDynamicExpression(arrayType.items, "x"), "))"]; + return [ + "map(", + typed, + ", λ(id x, ", + this.toDynamicExpression(arrayType.items, "x"), + "))", + ]; }, - _classType => ["[", typed, " JSONDictionary]"], - mapType => { + (_classType) => ["[", typed, " JSONDictionary]"], + (mapType) => { if (this.implicitlyConvertsFromJSON(mapType)) { // TODO check each value type return typed; } - return ["map(", typed, ", λ(id x, ", this.toDynamicExpression(mapType.values, "x"), "))"]; + return [ + "map(", + typed, + ", λ(id x, ", + this.toDynamicExpression(mapType.values, "x"), + "))", + ]; }, - _enumType => ["[", typed, " value]"], - unionType => { + (_enumType) => ["[", typed, " value]"], + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { if (this.implicitlyConvertsFromJSON(nullable)) { return ["NSNullify(", typed, ")"]; - } else { - return ["NSNullify(", this.toDynamicExpression(nullable, typed), ")"]; } - } else { - // TODO support unions - return typed; + + return [ + "NSNullify(", + this.toDynamicExpression(nullable, typed), + ")", + ]; } - } + + // TODO support unions + return typed; + }, ); } protected implicitlyConvertsFromJSON(t: Type): boolean { if (t instanceof ClassType) { return false; - } else if (t instanceof EnumType) { + } + if (t instanceof EnumType) { return false; - } else if (t instanceof ArrayType) { + } + if (t instanceof ArrayType) { return this.implicitlyConvertsFromJSON(t.items); - } else if (t instanceof MapType) { + } + if (t instanceof MapType) { return this.implicitlyConvertsFromJSON(t.values); - } else if (t.isPrimitive()) { + } + if (t.isPrimitive()) { return true; - } else if (t instanceof UnionType) { + } + if (t instanceof UnionType) { const nullable = nullableFromUnion(t); if (nullable !== null) { return this.implicitlyConvertsFromJSON(nullable); - } else { - // We don't support unions yet, so this is just untyped - return true; } - } else { - return false; + + // We don't support unions yet, so this is just untyped + return true; } + + return false; } protected implicitlyConvertsToJSON(t: Type): boolean { return this.implicitlyConvertsFromJSON(t) && "bool" !== t.kind; } - protected emitPropertyAssignment(propertyName: Name, jsonName: string, propertyType: Type): void { + protected emitPropertyAssignment( + propertyName: Name, + jsonName: string, + propertyType: Type, + ): void { const name = ["_", propertyName]; matchType( propertyType, - anyType => this.emitLine(name, " = ", this.fromDynamicExpression(anyType, name), ";"), - nullType => this.emitLine(name, " = ", this.fromDynamicExpression(nullType, name), ";"), - boolType => this.emitLine(name, " = ", this.fromDynamicExpression(boolType, name), ";"), - integerType => this.emitLine(name, " = ", this.fromDynamicExpression(integerType, name), ";"), - doubleType => this.emitLine(name, " = ", this.fromDynamicExpression(doubleType, name), ";"), - stringType => this.emitLine(name, " = ", this.fromDynamicExpression(stringType, name), ";"), - arrayType => this.emitLine(name, " = ", this.fromDynamicExpression(arrayType, name), ";"), - classType => this.emitLine(name, " = ", this.fromDynamicExpression(classType, ["(id)", name]), ";"), - mapType => { + (anyType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(anyType, name), + ";", + ), + (nullType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(nullType, name), + ";", + ), + (boolType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(boolType, name), + ";", + ), + (integerType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(integerType, name), + ";", + ), + (doubleType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(doubleType, name), + ";", + ), + (stringType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(stringType, name), + ";", + ), + (arrayType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(arrayType, name), + ";", + ), + (classType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(classType, ["(id)", name]), + ";", + ), + (mapType) => { const itemType = mapType.values; this.emitLine( name, " = map(", name, ", ", - ["λ(id x, ", this.fromDynamicExpression(itemType, "x"), ")"], - ");" + [ + "λ(id x, ", + this.fromDynamicExpression(itemType, "x"), + ")", + ], + ");", ); }, - enumType => this.emitLine(name, " = ", this.fromDynamicExpression(enumType, ["(id)", name]), ";"), - unionType => { + (enumType) => + this.emitLine( + name, + " = ", + this.fromDynamicExpression(enumType, ["(id)", name]), + ";", + ), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { - this.emitPropertyAssignment(propertyName, jsonName, nullable); + this.emitPropertyAssignment( + propertyName, + jsonName, + nullable, + ); } else { // TODO This is a union, but for now we just leave it dynamic - this.emitLine(name, " = ", this.fromDynamicExpression(unionType, name), ";"); + this.emitLine( + name, + " = ", + this.fromDynamicExpression(unionType, name), + ";", + ); } - } + }, ); } protected emitPrivateClassInterface(_: ClassType, name: Name): void { this.emitLine("@interface ", name, " (JSONConversion)"); - this.emitLine("+ (instancetype)fromJSONDictionary:(NSDictionary *)dict;"); + this.emitLine( + "+ (instancetype)fromJSONDictionary:(NSDictionary *)dict;", + ); this.emitLine("- (NSDictionary *)JSONDictionary;"); this.emitLine("@end"); } @@ -345,27 +530,57 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } private emitNonClassTopLevelTypedef(t: Type, name: Name): void { - let nonPointerTypeName = this.objcType(t)[0]; + const nonPointerTypeName = this.objcType(t)[0]; this.emitLine("typedef ", nonPointerTypeName, " ", name, ";"); } private topLevelFromDataPrototype(name: Name): Sourcelike { - return [name, " *_Nullable ", name, "FromData(NSData *data, NSError **error)"]; + return [ + name, + " *_Nullable ", + name, + "FromData(NSData *data, NSError **error)", + ]; } private topLevelFromJSONPrototype(name: Name): Sourcelike { - return [name, " *_Nullable ", name, "FromJSON(NSString *json, NSStringEncoding encoding, NSError **error)"]; + return [ + name, + " *_Nullable ", + name, + "FromJSON(NSString *json, NSStringEncoding encoding, NSError **error)", + ]; } 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)"]; + 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 { const parameter = this.variableNameForTopLevel(name); - const padding = pad ? repeatString(" ", this.sourcelikeToString(name).length - "NSString".length) : ""; + const padding = pad + ? repeatString( + " ", + this.sourcelikeToString(name).length - "NSString".length, + ) + : ""; return [ "NSString", padding, @@ -375,7 +590,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { name, " *", parameter, - ", NSStringEncoding encoding, NSError **error)" + ", NSStringEncoding encoding, NSError **error)", ]; } @@ -392,7 +607,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { 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(); }); @@ -407,37 +622,57 @@ 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 *error ? nil : ", this.fromDynamicExpression(t, "json"), ";"); }, - () => this.emitLine("return nil;") + () => this.emitLine("return nil;"), ); }); this.ensureBlankLine(); this.emitMethod(this.topLevelFromJSONPrototype(name), () => { - this.emitLine("return ", name, "FromData([json dataUsingEncoding:encoding], error);"); + this.emitLine( + "return ", + name, + "FromData([json dataUsingEncoding:encoding], error);", + ); }); this.ensureBlankLine(); this.emitMethod(this.topLevelToDataPrototype(name), () => { this.emitTryCatchAsError( () => { - this.emitLine("id json = ", this.toDynamicExpression(t, parameter), ";"); this.emitLine( - "NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:error];" + "id json = ", + this.toDynamicExpression(t, parameter), + ";", + ); + this.emitLine( + "NSData *data = [NSJSONSerialization dataWithJSONObject:json options:kNilOptions error:error];", ); this.emitLine("return *error ? nil : data;"); }, - () => this.emitLine("return nil;") + () => this.emitLine("return nil;"), ); }); this.ensureBlankLine(); this.emitMethod(this.topLevelToJSONPrototype(name), () => { - this.emitLine("NSData *data = ", name, "ToData(", parameter, ", error);"); - this.emitLine("return data ? [[NSString alloc] initWithData:data encoding:encoding] : nil;"); + this.emitLine( + "NSData *data = ", + name, + "ToData(", + parameter, + ", error);", + ); + this.emitLine( + "return data ? [[NSString alloc] initWithData:data encoding:encoding] : nil;", + ); }); } @@ -447,19 +682,22 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitDescription(this.descriptionForType(t)); this.emitLine("@interface ", className, " : NSObject"); - if (DEBUG) this.emitLine("@property NSDictionary *_json;"); + if (DEBUG) + this.emitLine("@property NSDictionary *_json;"); this.emitPropertyTable(t, (name, _json, property) => { - let attributes = ["nonatomic"]; + const attributes = ["nonatomic"]; // TODO offer a 'readonly' option // TODO We must add "copy" if it's NSCopy, otherwise "strong" if (property.type.isNullable) { attributes.push("nullable"); } - attributes.push(this.memoryAttribute(property.type, property.type.isNullable)); + attributes.push( + this.memoryAttribute(property.type, property.type.isNullable), + ); return [ ["@property ", ["(", attributes.join(", "), ")"], " "], - [this.pointerAwareTypeName(property.type), name, ";"] + [this.pointerAwareTypeName(property.type), name, ";"], ]; }); @@ -467,13 +705,17 @@ 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;" + "+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error;", + ); + this.emitLine( + "- (NSString *_Nullable)toJSON:(NSStringEncoding)encoding error:(NSError *_Nullable *)error;", + ); + this.emitLine( + "- (NSData *_Nullable)toData:(NSError *_Nullable *)error;", ); - this.emitLine("- (NSData *_Nullable)toData:(NSError *_Nullable *)error;"); } this.emitLine("@end"); @@ -482,7 +724,9 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { protected hasIrregularProperties(t: ClassType): boolean { let irregular = false; this.forEachClassProperty(t, "none", (name, jsonName) => { - irregular = irregular || stringEscape(jsonName) !== this.sourcelikeToString(name); + irregular = + irregular || + stringEscape(jsonName) !== this.sourcelikeToString(name); }); return irregular; } @@ -504,58 +748,110 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@implementation ", className); if (!this._options.justTypes) { - this.emitMethod("+ (NSDictionary *)properties", () => { - this.emitLine("static NSDictionary *properties;"); - this.emitLine("return properties = properties ? properties : @{"); - this.indent(() => { - this.forEachClassProperty(t, "none", (name, jsonName) => - this.emitLine(`@"${stringEscape(jsonName)}": @"`, name, '",') + this.emitMethod( + "+ (NSDictionary *)properties", + () => { + this.emitLine( + "static NSDictionary *properties;", ); - }); - this.emitLine("};"); - }); + this.emitLine( + "return properties = properties ? properties : @{", + ); + this.indent(() => { + this.forEachClassProperty(t, "none", (name, jsonName) => + this.emitLine( + `@"${stringEscape(jsonName)}": @"`, + name, + '",', + ), + ); + }); + this.emitLine("};"); + }, + ); this.ensureBlankLine(); if (isTopLevel) { this.emitMethod( "+ (_Nullable instancetype)fromData:(NSData *)data error:(NSError *_Nullable *)error", () => { - this.emitLine("return ", className, "FromData(data, 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.emitLine( + "return ", + className, + "FromJSON(json, encoding, error);", + ); + }, ); this.ensureBlankLine(); } - this.emitMethod("+ (instancetype)fromJSONDictionary:(NSDictionary *)dict", () => { - this.emitLine("return dict ? [[", className, " alloc] initWithJSONDictionary:dict] : nil;"); - }); + this.emitMethod( + "+ (instancetype)fromJSONDictionary:(NSDictionary *)dict", + () => { + this.emitLine( + "return dict ? [[", + className, + " alloc] initWithJSONDictionary:dict] : nil;", + ); + }, + ); this.ensureBlankLine(); - this.emitMethod("- (instancetype)initWithJSONDictionary:(NSDictionary *)dict", () => { - this.emitBlock("if (self = [super init])", () => { - if (DEBUG) this.emitLine("__json = dict;"); + this.emitMethod( + "- (instancetype)initWithJSONDictionary:(NSDictionary *)dict", + () => { + this.emitBlock("if (self = [super init])", () => { + if (DEBUG) this.emitLine("__json = dict;"); - this.emitLine("[self setValuesForKeysWithDictionary:dict];"); - this.forEachClassProperty(t, "none", (name, jsonName, property) => { - if (!this.implicitlyConvertsFromJSON(property.type)) { - this.emitPropertyAssignment(name, jsonName, property.type); - } + this.emitLine( + "[self setValuesForKeysWithDictionary:dict];", + ); + this.forEachClassProperty( + t, + "none", + (name, jsonName, property) => { + if ( + !this.implicitlyConvertsFromJSON( + property.type, + ) + ) { + this.emitPropertyAssignment( + name, + jsonName, + property.type, + ); + } + }, + ); }); - }); - this.emitLine("return self;"); - }); + this.emitLine("return self;"); + }, + ); this.ensureBlankLine(); - this.emitMethod("- (void)setValue:(nullable id)value forKey:(NSString *)key", () => { - this.emitLine("id resolved = ", className, ".properties[key];"); - this.emitLine("if (resolved) [super setValue:value forKey:resolved];"); - }); + this.emitMethod( + "- (void)setValue:(nullable id)value forKey:(NSString *)key", + () => { + this.emitLine( + "id resolved = ", + className, + ".properties[key];", + ); + this.emitLine( + "if (resolved) [super setValue:value forKey:resolved];", + ); + }, + ); // setNilValueForKey: is automatically invoked by the NSObject setValue:forKey: when it is passed nil for a scalar (a.k.a. non-nullable) object // The approach below sets the scalar to 0 in this case, and therefore assumes an initializer with incomplete data shouldn't be grounds for raising an exception. @@ -563,32 +859,54 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitMethod("- (void)setNilValueForKey:(NSString *)key", () => { this.emitLine("id resolved = ", className, ".properties[key];"); - this.emitLine("if (resolved) [super setValue:@(0) forKey:resolved];"); + this.emitLine( + "if (resolved) [super setValue:@(0) forKey:resolved];", + ); }); this.ensureBlankLine(); this.emitMethod("- (NSDictionary *)JSONDictionary", () => { if (!hasIrregularProperties && !hasUnsafeProperties) { - this.emitLine("return [self dictionaryWithValuesForKeys:", className, ".properties.allValues];"); + this.emitLine( + "return [self dictionaryWithValuesForKeys:", + className, + ".properties.allValues];", + ); return; } 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.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];", + ); + }, + ); + }, + ); } if (hasUnsafeProperties) { @@ -596,13 +914,30 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitExtraComments("Map values that need translation"); this.emitLine("[dict addEntriesFromDictionary:@{"); this.indent(() => { - this.forEachClassProperty(t, "none", (propertyName, jsonKey, property) => { - if (!this.implicitlyConvertsToJSON(property.type)) { - const key = stringEscape(jsonKey); - const name = ["_", propertyName]; - this.emitLine('@"', key, '": ', this.toDynamicExpression(property.type, name), ","); - } - }); + this.forEachClassProperty( + t, + "none", + (propertyName, jsonKey, property) => { + if ( + !this.implicitlyConvertsToJSON( + property.type, + ) + ) { + const key = stringEscape(jsonKey); + const name = ["_", propertyName]; + this.emitLine( + '@"', + key, + '": ', + this.toDynamicExpression( + property.type, + name, + ), + ",", + ); + } + }, + ); }); this.emitLine("}];"); } @@ -613,15 +948,26 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (isTopLevel) { this.ensureBlankLine(); - this.emitMethod("- (NSData *_Nullable)toData:(NSError *_Nullable *)error", () => { - this.emitLine("return ", className, "ToData(self, 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", () => { - this.emitLine("return ", className, "ToJSON(self, encoding, error);"); - } + this.emitLine( + "return ", + className, + "ToJSON(self, encoding, error);", + ); + }, ); } } @@ -636,7 +982,7 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { } protected variableNameForTopLevel(name: Name): Sourcelike { - const camelCaseName = modifySource(serialized => { + const camelCaseName = modifySource((serialized) => { // 1. remove class prefix serialized = serialized.slice(this._classPrefix.length); // 2. camel case @@ -657,29 +1003,53 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.emitLine("@end"); } - private emitPseudoEnumImplementation(enumType: EnumType, enumName: Name): void { + private emitPseudoEnumImplementation( + enumType: EnumType, + enumName: Name, + ): void { this.emitLine("@implementation ", enumName); const instances = [enumName, ".", staticEnumValuesIdentifier]; - this.emitMethod(["+ (NSDictionary *)", staticEnumValuesIdentifier], () => { - this.emitLine("static NSDictionary *", staticEnumValuesIdentifier, ";"); - this.emitLine( - "return ", + this.emitMethod( + [ + "+ (NSDictionary *)", staticEnumValuesIdentifier, - " = ", - staticEnumValuesIdentifier, - " ? ", - staticEnumValuesIdentifier, - " : @{" - ); - this.indent(() => { - this.forEachEnumCase(enumType, "none", (_, jsonValue) => { - const value = ['@"', stringEscape(jsonValue), '"']; - this.emitLine(value, ": [[", enumName, " alloc] initWithValue:", value, "],"); + ], + () => { + this.emitLine( + "static NSDictionary *", + staticEnumValuesIdentifier, + ";", + ); + this.emitLine( + "return ", + staticEnumValuesIdentifier, + " = ", + staticEnumValuesIdentifier, + " ? ", + staticEnumValuesIdentifier, + " : @{", + ); + this.indent(() => { + this.forEachEnumCase(enumType, "none", (_, jsonValue) => { + const value = ['@"', stringEscape(jsonValue), '"']; + this.emitLine( + value, + ": [[", + enumName, + " alloc] initWithValue:", + value, + "],", + ); + }); }); - }); - this.emitLine("};"); - }); + this.emitLine("};"); + }, + ); this.ensureBlankLine(); this.forEachEnumCase(enumType, "none", (name, jsonValue) => { @@ -692,20 +1062,24 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { instances, '[@"', stringEscape(jsonValue), - '"]; }' + '"]; }', ); }); this.ensureBlankLine(); - this.emitMethod("+ (instancetype _Nullable)withValue:(NSString *)value", () => - this.emitLine("return ", instances, "[value];") + this.emitMethod( + "+ (instancetype _Nullable)withValue:(NSString *)value", + () => this.emitLine("return ", instances, "[value];"), ); this.ensureBlankLine(); - this.emitMethod("- (instancetype)initWithValue:(NSString *)value", () => { - this.emitLine("if (self = [super init]) _value = value;"); - this.emitLine("return self;"); - }); + this.emitMethod( + "- (instancetype)initWithValue:(NSString *)value", + () => { + this.emitLine("if (self = [super init]) _value = value;"); + this.emitLine("return self;"); + }, + ); this.ensureBlankLine(); this.emitLine("- (NSUInteger)hash { return _value.hash; }"); @@ -717,7 +1091,9 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { 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"; + proposedFilename = + this.sourcelikeToString(this.nameForNamedType(firstTopLevel)) + + ".m"; } const [filename, extension] = splitExtension(proposedFilename); @@ -733,15 +1109,22 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.forEachTopLevel("none", (t, topLevelName) => { const fromJsonExpression = t instanceof ClassType - ? ["[", topLevelName, " fromJSON:json encoding:NSUTF8Encoding error:&error];"] - : [topLevelName, "FromJSON(json, NSUTF8Encoding, &error);"]; + ? [ + "[", + topLevelName, + " fromJSON:json encoding:NSUTF8Encoding error:&error];", + ] + : [ + topLevelName, + "FromJSON(json, NSUTF8Encoding, &error);", + ]; this.emitLine( "// ", topLevelName, " *", this.variableNameForTopLevel(topLevelName), " = ", - fromJsonExpression + fromJsonExpression, ); }); } @@ -753,9 +1136,10 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { // Emit @class declarations for top-level array+maps and classes this.forEachNamedType( "none", - (_: ClassType, className: Name) => this.emitLine("@class ", className, ";"), + (_: ClassType, className: Name) => + this.emitLine("@class ", className, ";"), (_, enumName) => this.emitLine("@class ", enumName, ";"), - () => null + () => null, ); this.ensureBlankLine(); @@ -765,18 +1149,26 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { if (this.haveEnums) { this.emitMark("Boxed enums"); - this.forEachEnum("leading-and-interposing", (t, n) => this.emitPseudoEnumInterface(t, n)); + this.forEachEnum("leading-and-interposing", (t, n) => + this.emitPseudoEnumInterface(t, n), + ); } // Emit interfaces for top-level array+maps and classes 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)); - if (!this._options.justTypes && (hasTopLevelNonClassTypes || this._options.marshallingFunctions)) { + const hasTopLevelNonClassTypes = iterableSome( + this.topLevels, + ([_, t]) => !(t instanceof ClassType), + ); + if ( + !this._options.justTypes && + (hasTopLevelNonClassTypes || this._options.marshallingFunctions) + ) { this.ensureBlankLine(); this.emitMark("Top-level marshaling functions"); this.forEachTopLevel( @@ -784,16 +1176,19 @@ 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), ); } this.emitMark("Object interfaces"); this.forEachNamedType( "leading-and-interposing", - (c: ClassType, className: Name) => this.emitClassInterface(c, className), + (c: ClassType, className: Name) => + this.emitClassInterface(c, className), + () => null, () => null, - () => null ); this.ensureBlankLine(); @@ -810,11 +1205,17 @@ 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.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"); @@ -828,9 +1229,10 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.forEachNamedType( "leading-and-interposing", - (c: ClassType, className: Name) => this.emitPrivateClassInterface(c, className), + (c: ClassType, className: Name) => + this.emitPrivateClassInterface(c, className), + () => null, () => null, - () => null ); if (this.haveEnums) { @@ -838,12 +1240,14 @@ 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)); + this.forEachEnum("leading-and-interposing", (t, n) => + this.emitPseudoEnumImplementation(t, n), + ); } this.ensureBlankLine(); @@ -851,14 +1255,17 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { this.ensureBlankLine(); this.emitMark("JSON serialization"); - this.forEachTopLevel("leading-and-interposing", (t, n) => this.emitTopLevelFunctions(t, n)); + this.forEachTopLevel("leading-and-interposing", (t, n) => + this.emitTopLevelFunctions(t, n), + ); } this.forEachNamedType( "leading-and-interposing", - (c: ClassType, className: Name) => this.emitClassImplementation(c, className), + (c: ClassType, className: Name) => + this.emitClassImplementation(c, className), + () => null, () => null, - () => null ); if (!this._options.justTypes) { @@ -876,7 +1283,8 @@ export class ObjectiveCRenderer extends ConvenienceRenderer { 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))) ); } diff --git a/packages/quicktype-core/src/language/Objective-C/constants.ts b/packages/quicktype-core/src/language/Objective-C/constants.ts index 84ec8f95..f483de6c 100644 --- a/packages/quicktype-core/src/language/Objective-C/constants.ts +++ b/packages/quicktype-core/src/language/Objective-C/constants.ts @@ -46,7 +46,7 @@ export const keywords = [ "unsigned", "void", "volatile", - "while" + "while", ] as const; export const forbiddenPropertyNames = [ @@ -58,7 +58,7 @@ export const forbiddenPropertyNames = [ "mutableCopy", "superclass", "debugDescription", - "new" + "new", ] as const; export const booleanPrefixes = [ @@ -78,5 +78,5 @@ export const booleanPrefixes = [ "requires", "require", "needs", - "need" + "need", ] as const; diff --git a/packages/quicktype-core/src/language/Objective-C/language.ts b/packages/quicktype-core/src/language/Objective-C/language.ts index a8b8b88a..09199da8 100644 --- a/packages/quicktype-core/src/language/Objective-C/language.ts +++ b/packages/quicktype-core/src/language/Objective-C/language.ts @@ -1,7 +1,12 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { ObjectiveCRenderer } from "./ObjectiveCRenderer"; import { DEFAULT_CLASS_PREFIX } from "./utils"; @@ -13,23 +18,34 @@ export const objectiveCOptions = { { all: { interface: true, implementation: true }, interface: { interface: true, implementation: false }, - implementation: { interface: false, implementation: true } + implementation: { interface: false, implementation: true }, } as const, - "all" + "all", ), 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) + 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 const objectiveCLanguageConfig = { displayName: "Objective-C", names: ["objc", "objective-c", "objectivec"], - extension: "m" + extension: "m", } as const; -export class ObjectiveCTargetLanguage extends TargetLanguage { +export class ObjectiveCTargetLanguage extends TargetLanguage< + typeof objectiveCLanguageConfig +> { public constructor() { super(objectiveCLanguageConfig); } @@ -38,7 +54,14 @@ export class ObjectiveCTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index cdff7db5..418dac6a 100644 --- a/packages/quicktype-core/src/language/Objective-C/utils.ts +++ b/packages/quicktype-core/src/language/Objective-C/utils.ts @@ -7,7 +7,7 @@ import { combineWords, firstUpperWordStyle, splitIntoWords, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../../support/Strings"; import { booleanPrefixes, forbiddenPropertyNames } from "./constants"; @@ -24,7 +24,7 @@ export function typeNameStyle(prefix: string, original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); return addPrefixIfNecessary(prefix, result); } @@ -41,8 +41,11 @@ export function propertyNameStyle(original: string, isBool = false): string { if (isBool) { if (words.length === 0) { words = [{ word: "flag", isAcronym: false }]; + } else if ( + !words[0].isAcronym && // @ts-expect-error needs strict type - } else if (!words[0].isAcronym && !booleanPrefixes.includes(words[0].word)) { + !booleanPrefixes.includes(words[0].word) + ) { words = [{ word: "is", isAcronym: false }, ...words]; } } @@ -62,7 +65,7 @@ export function propertyNameStyle(original: string, isBool = false): string { allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -72,7 +75,10 @@ function isStartCharacter(utf16Unit: number): boolean { function isPartCharacter(utf16Unit: number): boolean { const category: string = unicode.getCategory(utf16Unit); - return ["Nd", "Pc", "Mn", "Mc"].includes(category) || isStartCharacter(utf16Unit); + return ( + ["Nd", "Pc", "Mn", "Mc"].includes(category) || + isStartCharacter(utf16Unit) + ); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); diff --git a/packages/quicktype-core/src/language/Php/PhpRenderer.ts b/packages/quicktype-core/src/language/Php/PhpRenderer.ts index b9d2a951..8dfb3c5e 100644 --- a/packages/quicktype-core/src/language/Php/PhpRenderer.ts +++ b/packages/quicktype-core/src/language/Php/PhpRenderer.ts @@ -1,18 +1,39 @@ import * as _ from "lodash"; -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 { + 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 { 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 "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import type { + ClassProperty, + ClassType, + EnumType, + Type, + UnionType, +} from "../../Type"; +import { + directlyReachableSingleNamedType, + matchType, + nullableFromUnion, +} from "../../Type/TypeUtils"; -import { type phpOptions } from "./language"; +import type { phpOptions } from "./language"; import { phpNameStyle, stringEscape } from "./utils"; export interface FunctionNames { @@ -25,7 +46,10 @@ export interface FunctionNames { } export class PhpRenderer extends ConvenienceRenderer { - private readonly _gettersAndSettersForPropertyName = new Map(); + private readonly _gettersAndSettersForPropertyName = new Map< + Name, + FunctionNames + >(); private _haveEmittedLeadingComments = false; @@ -36,12 +60,15 @@ export class PhpRenderer extends ConvenienceRenderer { 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 }; } @@ -74,37 +101,37 @@ export class PhpRenderer extends ConvenienceRenderer { _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, @@ -112,7 +139,7 @@ export class PhpRenderer extends ConvenienceRenderer { validate: validateName, from: fromName, to: toName, - sample: sampleName + sample: sampleName, }; } @@ -121,9 +148,15 @@ export class PhpRenderer extends ConvenienceRenderer { className: Name, p: ClassProperty, jsonName: string, - name: Name + name: Name, ): Name[] { - const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter(c, className, p, jsonName, name); + const getterAndSetterNames = this.makeNamesForPropertyGetterAndSetter( + c, + className, + p, + jsonName, + name, + ); this._gettersAndSettersForPropertyName.set(name, getterAndSetterNames); return [ getterAndSetterNames.getter, @@ -131,28 +164,46 @@ 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 } = { - typeNamingFunction: funPrefixNamer("types", n => - phpNameStyle(true, false, n, acronymStyle(this._options.acronymStyle)) + typeNamingFunction: funPrefixNamer("types", (n) => + phpNameStyle( + true, + false, + n, + acronymStyle(this._options.acronymStyle), + ), ), - propertyNamingFunction: funPrefixNamer("properties", n => - phpNameStyle(false, false, n, acronymStyle(this._options.acronymStyle)) + propertyNamingFunction: funPrefixNamer("properties", (n) => + phpNameStyle( + false, + false, + n, + acronymStyle(this._options.acronymStyle), + ), + ), + enumCaseNamingFunction: funPrefixNamer("enum-cases", (n) => + phpNameStyle( + true, + true, + n, + acronymStyle(this._options.acronymStyle), + ), ), - enumCaseNamingFunction: funPrefixNamer("enum-cases", n => - phpNameStyle(true, true, n, acronymStyle(this._options.acronymStyle)) - ) }; return styling[convention]; } protected startFile(_basename: Sourcelike): void { this.ensureBlankLine(); - if (!this._haveEmittedLeadingComments && this.leadingComments !== undefined) { + if ( + !this._haveEmittedLeadingComments && + this.leadingComments !== undefined + ) { this.emitComments(this.leadingComments); this.ensureBlankLine(); this._haveEmittedLeadingComments = true; @@ -170,7 +221,11 @@ export class PhpRenderer extends ConvenienceRenderer { } public emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + this.emitCommentLines(lines, { + lineStart: " * ", + beforeComment: "/**", + afterComment: " */", + }); } public emitBlock(line: Sourcelike, f: () => void): void { @@ -179,29 +234,38 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine("}"); } - protected phpType(_reference: boolean, t: Type, isOptional = false, prefix = "?", suffix = ""): Sourcelike { + protected phpType( + _reference: boolean, + t: Type, + isOptional = false, + prefix = "?", + suffix = "", + ): Sourcelike { function optionalize(s: Sourcelike): Sourcelike { return [isOptional ? prefix : "", s, isOptional ? suffix : ""]; } return matchType( t, - _anyType => maybeAnnotated(isOptional, anyTypeIssueAnnotation, "Object"), - _nullType => maybeAnnotated(isOptional, nullTypeIssueAnnotation, "Object"), - _boolType => optionalize("bool"), - _integerType => optionalize("int"), - _doubleType => optionalize("float"), - _stringType => optionalize("string"), - _arrayType => optionalize("array"), - classType => optionalize(this.nameForNamedType(classType)), - _mapType => optionalize("stdClass"), - enumType => optionalize(this.nameForNamedType(enumType)), - unionType => { + (_anyType) => + maybeAnnotated(isOptional, anyTypeIssueAnnotation, "Object"), + (_nullType) => + maybeAnnotated(isOptional, nullTypeIssueAnnotation, "Object"), + (_boolType) => optionalize("bool"), + (_integerType) => optionalize("int"), + (_doubleType) => optionalize("float"), + (_stringType) => optionalize("string"), + (_arrayType) => optionalize("array"), + (classType) => optionalize(this.nameForNamedType(classType)), + (_mapType) => optionalize("stdClass"), + (enumType) => optionalize(this.nameForNamedType(enumType)), + (unionType) => { const nullable = nullableFromUnion(unionType); - if (nullable !== null) return this.phpType(true, nullable, true, prefix, suffix); + if (nullable !== null) + return this.phpType(true, nullable, true, prefix, suffix); return this.nameForNamedType(unionType); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "time") { throw Error('transformedStringType.kind === "time"'); } @@ -219,55 +283,61 @@ export class PhpRenderer extends ConvenienceRenderer { } return "string"; - } + }, ); } protected phpDocConvertType(className: Name, t: Type): Sourcelike { return matchType( t, - _anyType => "any", - _nullType => "null", - _boolType => "bool", - _integerType => "int", - _doubleType => "float", - _stringType => "string", - arrayType => [this.phpDocConvertType(className, arrayType.items), "[]"], - _classType => _classType.getCombinedName(), - _mapType => "stdClass", - enumType => this.nameForNamedType(enumType), - unionType => { + (_anyType) => "any", + (_nullType) => "null", + (_boolType) => "bool", + (_integerType) => "int", + (_doubleType) => "float", + (_stringType) => "string", + (arrayType) => [ + this.phpDocConvertType(className, arrayType.items), + "[]", + ], + (_classType) => _classType.getCombinedName(), + (_mapType) => "stdClass", + (enumType) => this.nameForNamedType(enumType), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { - return [this.phpDocConvertType(className, nullable), "|null"]; + return [ + this.phpDocConvertType(className, nullable), + "|null", + ]; } throw Error("union are not supported"); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return "DateTime"; } throw Error('transformedStringType.kind === "unknown"'); - } + }, ); } protected phpConvertType(className: Name, t: Type): Sourcelike { return matchType( t, - _anyType => "any", - _nullType => "null", - _boolType => "bool", - _integerType => "int", - _doubleType => "float", - _stringType => "string", - _arrayType => "array", - _classType => "stdClass", - _mapType => "stdClass", - _enumType => "string", // TODO number this.nameForNamedType(enumType), - unionType => { + (_anyType) => "any", + (_nullType) => "null", + (_boolType) => "bool", + (_integerType) => "int", + (_doubleType) => "float", + (_stringType) => "string", + (_arrayType) => "array", + (_classType) => "stdClass", + (_mapType) => "stdClass", + (_enumType) => "string", // TODO number this.nameForNamedType(enumType), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { return ["?", this.phpConvertType(className, nullable)]; @@ -275,50 +345,76 @@ export class PhpRenderer extends ConvenienceRenderer { throw Error("union are not supported"); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return "string"; } throw Error('transformedStringType.kind === "unknown"'); - } + }, ); } - protected phpToObjConvert(className: Name, t: Type, lhs: Sourcelike[], args: Sourcelike[]): void { + protected phpToObjConvert( + className: Name, + t: Type, + lhs: Sourcelike[], + args: Sourcelike[], + ): void { matchType( t, - _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), - _nullType => this.emitLine(...lhs, ...args, "; /*null*/"), - _boolType => this.emitLine(...lhs, ...args, "; /*bool*/"), - _integerType => this.emitLine(...lhs, ...args, "; /*int*/"), - _doubleType => this.emitLine(...lhs, ...args, "; /*float*/"), - _stringType => this.emitLine(...lhs, ...args, "; /*string*/"), - arrayType => { + (_anyType) => this.emitLine(...lhs, ...args, "; /*any*/"), + (_nullType) => this.emitLine(...lhs, ...args, "; /*null*/"), + (_boolType) => this.emitLine(...lhs, ...args, "; /*bool*/"), + (_integerType) => this.emitLine(...lhs, ...args, "; /*int*/"), + (_doubleType) => this.emitLine(...lhs, ...args, "; /*float*/"), + (_stringType) => this.emitLine(...lhs, ...args, "; /*string*/"), + (arrayType) => { this.emitLine(...lhs, "array_map(function ($value) {"); this.indent(() => { - this.phpToObjConvert(className, arrayType.items, ["return "], ["$value"]); + this.phpToObjConvert( + className, + arrayType.items, + ["return "], + ["$value"], + ); // this.emitLine("return $tmp;"); }); this.emitLine("}, ", ...args, ");"); }, - _classType => this.emitLine(...lhs, ...args, "->to(); ", "/*class*/"), - mapType => { + (_classType) => + this.emitLine(...lhs, ...args, "->to(); ", "/*class*/"), + (mapType) => { this.emitBlock(["function to($my): stdClass"], () => { this.emitLine("$out = new stdClass();"); this.emitBlock(["foreach ($my as $k => $v)"], () => { - this.phpToObjConvert(className, mapType.values, ["$my->$k = "], ["$v"]); + this.phpToObjConvert( + className, + mapType.values, + ["$my->$k = "], + ["$v"], + ); }); this.emitLine("return $out;"); }); this.emitLine("return to(", ...args, ");"); }, - enumType => this.emitLine(...lhs, this.nameForNamedType(enumType), "::to(", ...args, "); ", "/*enum*/"), - unionType => { + (enumType) => + this.emitLine( + ...lhs, + this.nameForNamedType(enumType), + "::to(", + ...args, + "); ", + "/*enum*/", + ), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { this.emitLine("if (!is_null(", ...args, ")) {"); - this.indent(() => this.phpToObjConvert(className, nullable, lhs, args)); + this.indent(() => + this.phpToObjConvert(className, nullable, lhs, args), + ); this.emitLine("} else {"); this.indent(() => this.emitLine(...lhs, " null;")); this.emitLine("}"); @@ -327,61 +423,107 @@ export class PhpRenderer extends ConvenienceRenderer { throw Error("union are not supported"); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { - this.emitLine(...lhs, ...args, "->format(DateTimeInterface::ISO8601);"); + this.emitLine( + ...lhs, + ...args, + "->format(DateTimeInterface::ISO8601);", + ); return; } throw Error('transformedStringType.kind === "unknown"'); - } + }, ); } - private transformDateTime(className: Name, attrName: Sourcelike, scopeAttrName: Sourcelike[]): void { + 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, "');") + 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[]): void { + protected phpFromObjConvert( + className: Name, + t: Type, + lhs: Sourcelike[], + args: Sourcelike[], + ): void { matchType( t, - _anyType => this.emitLine(...lhs, ...args, "; /*any*/"), - _nullType => this.emitLine(...lhs, ...args, "; /*null*/"), - _boolType => this.emitLine(...lhs, ...args, "; /*bool*/"), - _integerType => this.emitLine(...lhs, ...args, "; /*int*/"), - _doubleType => this.emitLine(...lhs, ...args, "; /*float*/"), - _stringType => this.emitLine(...lhs, ...args, "; /*string*/"), - arrayType => { + (_anyType) => this.emitLine(...lhs, ...args, "; /*any*/"), + (_nullType) => this.emitLine(...lhs, ...args, "; /*null*/"), + (_boolType) => this.emitLine(...lhs, ...args, "; /*bool*/"), + (_integerType) => this.emitLine(...lhs, ...args, "; /*int*/"), + (_doubleType) => this.emitLine(...lhs, ...args, "; /*float*/"), + (_stringType) => this.emitLine(...lhs, ...args, "; /*string*/"), + (arrayType) => { this.emitLine(...lhs, " array_map(function ($value) {"); this.indent(() => { - this.phpFromObjConvert(className, arrayType.items, ["return "], ["$value"]); + this.phpFromObjConvert( + className, + arrayType.items, + ["return "], + ["$value"], + ); // this.emitLine("return $tmp;"); }); this.emitLine("}, ", ...args, ");"); }, - classType => - this.emitLine(...lhs, this.nameForNamedType(classType), "::from(", ...args, "); ", "/*class*/"), - mapType => { + (classType) => + this.emitLine( + ...lhs, + this.nameForNamedType(classType), + "::from(", + ...args, + "); ", + "/*class*/", + ), + (mapType) => { this.emitBlock(["function from($my): stdClass"], () => { this.emitLine("$out = new stdClass();"); this.emitBlock(["foreach ($my as $k => $v)"], () => { - this.phpFromObjConvert(className, mapType.values, ["$out->$k = "], ["$v"]); + this.phpFromObjConvert( + className, + mapType.values, + ["$out->$k = "], + ["$v"], + ); }); this.emitLine("return $out;"); }); this.emitLine("return from(", ...args, ");"); }, - enumType => this.emitLine(...lhs, this.nameForNamedType(enumType), "::from(", ...args, "); ", "/*enum*/"), - unionType => { + (enumType) => + this.emitLine( + ...lhs, + this.nameForNamedType(enumType), + "::from(", + ...args, + "); ", + "/*enum*/", + ), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { this.emitLine("if (!is_null(", ...args, ")) {"); - this.indent(() => this.phpFromObjConvert(className, nullable, lhs, args)); + this.indent(() => + this.phpFromObjConvert(className, nullable, lhs, args), + ); this.emitLine("} else {"); this.indent(() => this.emitLine("return null;")); this.emitLine("}"); @@ -390,16 +532,21 @@ export class PhpRenderer extends ConvenienceRenderer { throw Error("union are not supported"); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { - this.emitLine("$tmp = ", "DateTime::createFromFormat(DateTimeInterface::ISO8601, ", args, ");"); + this.emitLine( + "$tmp = ", + "DateTime::createFromFormat(DateTimeInterface::ISO8601, ", + args, + ");", + ); this.transformDateTime(className, "", ["$tmp"]); this.emitLine("return $tmp;"); return; } throw Error('transformedStringType.kind === "unknown"'); - } + }, ); } @@ -409,11 +556,11 @@ export class PhpRenderer extends ConvenienceRenderer { lhs: Sourcelike[], args: Sourcelike[], idx: number, - suffix: Sourcelike + suffix: Sourcelike, ): void { matchType( t, - _anyType => + (_anyType) => this.emitLine( ...lhs, "'AnyType::", @@ -427,13 +574,53 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/" + "*/", ), - _nullType => this.emitLine(...lhs, "null", suffix, " /*", "" + idx, ":", args, "*/"), - _boolType => this.emitLine(...lhs, "true", suffix, " /*", "" + idx, ":", args, "*/"), - _integerType => this.emitLine(...lhs, "" + idx, suffix, " /*", "" + idx, ":", args, "*/"), - _doubleType => this.emitLine(...lhs, "" + (idx + idx / 1000), suffix, " /*", "" + idx, ":", args, "*/"), - _stringType => + (_nullType) => + this.emitLine( + ...lhs, + "null", + suffix, + " /*", + "" + idx, + ":", + args, + "*/", + ), + (_boolType) => + this.emitLine( + ...lhs, + "true", + suffix, + " /*", + "" + idx, + ":", + args, + "*/", + ), + (_integerType) => + this.emitLine( + ...lhs, + "" + idx, + suffix, + " /*", + "" + idx, + ":", + args, + "*/", + ), + (_doubleType) => + this.emitLine( + ...lhs, + "" + (idx + idx / 1000), + suffix, + " /*", + "" + idx, + ":", + args, + "*/", + ), + (_stringType) => this.emitLine( ...lhs, "'", @@ -447,16 +634,23 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/" + "*/", ), - arrayType => { + (arrayType) => { this.emitLine(...lhs, " array("); this.indent(() => { - this.phpSampleConvert(className, arrayType.items, [], [], idx, ""); + this.phpSampleConvert( + className, + arrayType.items, + [], + [], + idx, + "", + ); }); this.emitLine("); /* ", "" + idx, ":", args, "*/"); }, - classType => + (classType) => this.emitLine( ...lhs, this.nameForNamedType(classType), @@ -466,27 +660,48 @@ export class PhpRenderer extends ConvenienceRenderer { "" + idx, ":", args, - "*/" + "*/", ), - mapType => { + (mapType) => { this.emitBlock(["function sample(): stdClass"], () => { this.emitLine("$out = new stdClass();"); - this.phpSampleConvert(className, mapType.values, ["$out->{'", className, "'} = "], args, idx, ";"); + this.phpSampleConvert( + className, + mapType.values, + ["$out->{'", className, "'} = "], + args, + idx, + ";", + ); this.emitLine("return $out;"); }); this.emitLine("return sample();"); }, - enumType => this.emitLine(...lhs, this.nameForNamedType(enumType), "::sample()", suffix, " /*enum*/"), - unionType => { + (enumType) => + this.emitLine( + ...lhs, + this.nameForNamedType(enumType), + "::sample()", + suffix, + " /*enum*/", + ), + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { - this.phpSampleConvert(className, nullable, lhs, args, idx, suffix); + this.phpSampleConvert( + className, + nullable, + lhs, + args, + idx, + suffix, + ); return; } - throw Error("union are not supported:" + unionType); + throw Error(`union are not supported:${unionType}`); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { const x = _.pad("" + (1 + (idx % 31)), 2, "0"); this.emitLine( @@ -494,72 +709,111 @@ export class PhpRenderer extends ConvenienceRenderer { "DateTime::createFromFormat(DateTimeInterface::ISO8601, '", `2020-12-${x}T12:${x}:${x}+00:00`, "')", - suffix + suffix, ); // this.emitLine("return sample();"); return; } throw Error('transformedStringType.kind === "unknown"'); - } + }, ); } - private phpValidate(className: Name, t: Type, attrName: Sourcelike, scopeAttrName: string): void { + 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, '");') + this.emitLine( + 'throw new Exception("Attribute Error:', + myT, + "::", + attrName, + '");', + ), ); }; matchType( t, - _anyType => is("defined"), - _nullType => is("is_null"), - _boolType => is("is_bool"), - _integerType => is("is_integer"), - _doubleType => is("is_float"), - _stringType => is("is_string"), - arrayType => { + (_anyType) => is("defined"), + (_nullType) => is("is_null"), + (_boolType) => is("is_bool"), + (_integerType) => is("is_integer"), + (_doubleType) => is("is_float"), + (_stringType) => is("is_string"), + (arrayType) => { is("is_array"); - this.emitLine("array_walk(", scopeAttrName, ", function(", scopeAttrName, "_v) {"); + this.emitLine( + "array_walk(", + scopeAttrName, + ", function(", + scopeAttrName, + "_v) {", + ); this.indent(() => { - this.phpValidate(className, arrayType.items, attrName, `${scopeAttrName}_v`); + this.phpValidate( + className, + arrayType.items, + attrName, + `${scopeAttrName}_v`, + ); }); this.emitLine("});"); }, - _classType => { + (_classType) => { this.emitLine(scopeAttrName, "->validate();"); }, - mapType => { + (mapType) => { this.emitLine("foreach (", scopeAttrName, " as $k => $v) {"); this.indent(() => { this.phpValidate(className, mapType.values, attrName, "$v"); }); this.emitLine("}"); }, - enumType => { - this.emitLine(this.phpType(false, enumType), "::to(", scopeAttrName, ");"); + (enumType) => { + this.emitLine( + this.phpType(false, enumType), + "::to(", + scopeAttrName, + ");", + ); }, - unionType => { + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { - this.emitBlock(["if (!is_null(", scopeAttrName, "))"], () => { - this.phpValidate(className, nullable, attrName, scopeAttrName); - }); + this.emitBlock( + ["if (!is_null(", scopeAttrName, "))"], + () => { + this.phpValidate( + className, + nullable, + attrName, + scopeAttrName, + ); + }, + ); return; } throw Error("not implemented"); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { - this.transformDateTime(className, attrName, [scopeAttrName]); + this.transformDateTime(className, attrName, [ + scopeAttrName, + ]); return; } - throw Error(`transformedStringType.kind === ${transformedStringType.kind}`); - } + throw Error( + `transformedStringType.kind === ${transformedStringType.kind}`, + ); + }, ); } @@ -568,7 +822,7 @@ export class PhpRenderer extends ConvenienceRenderer { p: ClassProperty, className: Name, _name: Name, - desc?: string[] + desc?: string[], ): void { this.emitLine("/**"); if (desc !== undefined) { @@ -577,7 +831,11 @@ export class PhpRenderer extends ConvenienceRenderer { } // this.emitLine(" * @param ", this.phpType(false, p.type, false, "", "|null")); - this.emitLine(" * @param ", this.phpConvertType(className, p.type), " $value"); + this.emitLine( + " * @param ", + this.phpConvertType(className, p.type), + " $value", + ); this.emitLine(" * @throws Exception"); this.emitLine(" * @return ", this.phpType(false, p.type)); this.emitLine(" */"); @@ -588,16 +846,27 @@ 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[]): void { + protected emitToMethod( + names: FunctionNames, + p: ClassProperty, + className: Name, + name: Name, + desc?: string[], + ): void { this.emitLine("/**"); if (desc !== undefined) { this.emitLine(" * ", desc); @@ -607,12 +876,42 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine(" * @throws Exception"); this.emitLine(" * @return ", this.phpConvertType(className, p.type)); this.emitLine(" */"); - this.emitBlock(["public function ", names.to, "(): ", this.phpConvertType(className, p.type)], () => { - this.emitBlock(["if (", className, "::", names.validate, "($this->", name, ")) "], () => { - this.phpToObjConvert(className, p.type, ["return "], ["$this->", name]); - }); - this.emitLine("throw new Exception('never get to this ", className, "::", name, "');"); - }); + this.emitBlock( + [ + "public function ", + names.to, + "(): ", + this.phpConvertType(className, p.type), + ], + () => { + this.emitBlock( + [ + "if (", + className, + "::", + names.validate, + "($this->", + name, + ")) ", + ], + () => { + this.phpToObjConvert( + className, + p.type, + ["return "], + ["$this->", name], + ); + }, + ); + this.emitLine( + "throw new Exception('never get to this ", + className, + "::", + name, + "');", + ); + }, + ); } protected emitValidateMethod( @@ -620,7 +919,7 @@ export class PhpRenderer extends ConvenienceRenderer { p: ClassProperty, className: Name, name: Name, - desc?: string[] + desc?: string[], ): void { this.emitLine("/**"); if (desc !== undefined) { @@ -628,16 +927,25 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine(" *"); } - this.emitLine(" * @param ", this.phpType(false, p.type, false, "", "|null")); + this.emitLine( + " * @param ", + this.phpType(false, p.type, false, "", "|null"), + ); this.emitLine(" * @return bool"); this.emitLine(" * @throws Exception"); this.emitLine(" */"); this.emitBlock( - ["public static function ", names.validate, "(", this.phpType(false, p.type), " $value): bool"], + [ + "public static function ", + names.validate, + "(", + this.phpType(false, p.type), + " $value): bool", + ], () => { this.phpValidate(className, p.type, name, "$value"); this.emitLine("return true;"); - } + }, ); } @@ -646,7 +954,7 @@ export class PhpRenderer extends ConvenienceRenderer { p: ClassProperty, className: Name, name: Name, - desc?: string[] + desc?: string[], ): void { if (this._options.withGet) { this.emitLine("/**"); @@ -662,24 +970,38 @@ export class PhpRenderer extends ConvenienceRenderer { const rendered = this.phpType(false, p.type); this.emitLine(" * @return ", rendered); this.emitLine(" */"); - this.emitBlock(["public function ", names.getter, "(): ", rendered], () => { - if (!this._options.fastGet) { - this.emitBlock(["if (", className, "::", names.validate, "($this->", name, ")) "], () => { + this.emitBlock( + ["public function ", names.getter, "(): ", rendered], + () => { + if (!this._options.fastGet) { + this.emitBlock( + [ + "if (", + className, + "::", + names.validate, + "($this->", + name, + ")) ", + ], + () => { + this.emitLine("return $this->", name, ";"); + }, + ); + this.emitLine( + "throw new Exception('never get to ", + names.getter, + " ", + className, + "::", + name, + "');", + ); + } else { this.emitLine("return $this->", name, ";"); - }); - this.emitLine( - "throw new Exception('never get to ", - names.getter, - " ", - className, - "::", - name, - "');" - ); - } else { - this.emitLine("return $this->", name, ";"); - } - }); + } + }, + ); } } @@ -688,7 +1010,7 @@ export class PhpRenderer extends ConvenienceRenderer { p: ClassProperty, className: Name, name: Name, - desc?: string[] + desc?: string[], ): void { if (this._options.withSet) { this.emitLine("/**"); @@ -697,14 +1019,29 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitLine(" *"); } - this.emitLine(" * @param ", this.phpType(false, p.type, false, "", "|null")); + this.emitLine( + " * @param ", + this.phpType(false, p.type, false, "", "|null"), + ); 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)) "], () => { - this.emitLine("$this->", name, " = $value;"); - }); - }); + this.emitBlock( + [ + "public function ", + names.setter, + "(", + this.phpType(false, p.type), + " $value)", + ], + () => { + this.emitBlock( + ["if (", className, "::", names.validate, "($value)) "], + () => { + this.emitLine("$this->", name, " = $value;"); + }, + ); + }, + ); } } @@ -714,7 +1051,7 @@ export class PhpRenderer extends ConvenienceRenderer { className: Name, name: Name, desc: string[] | undefined, - idx: number + idx: number, ): void { if (this._options.withGet) { this.emitLine("/**"); @@ -726,9 +1063,19 @@ export class PhpRenderer extends ConvenienceRenderer { const rendered = this.phpType(false, p.type); this.emitLine(" * @return ", rendered); this.emitLine(" */"); - this.emitBlock(["public static function ", names.sample, "(): ", rendered], () => { - this.phpSampleConvert(className, p.type, ["return "], [name], idx, ";"); - }); + this.emitBlock( + ["public static function ", names.sample, "(): ", rendered], + () => { + this.phpSampleConvert( + className, + p.type, + ["return "], + [name], + idx, + ";", + ); + }, + ); } } @@ -745,7 +1092,7 @@ export class PhpRenderer extends ConvenienceRenderer { "; // json:", jsonName, " ", - p.type.isNullable ? "Optional" : "Required" + p.type.isNullable ? "Optional" : "Required", ); }); @@ -756,48 +1103,102 @@ export class PhpRenderer extends ConvenienceRenderer { this.forEachClassProperty(c, "none", (name, __, p) => { args.push([prefix, this.phpType(false, p.type), " $", name]); prefix = ", "; - comments.push([" * @param ", this.phpType(false, p.type, false, "", "|null"), " $", name, "\n"]); - }); - this.emitBlock(["/**\n", ...comments, " */\n", "public function __construct(", ...args, ")"], () => { - this.forEachClassProperty(c, "none", name => { - this.emitLine("$this->", name, " = $", name, ";"); - }); + comments.push([ + " * @param ", + this.phpType(false, p.type, false, "", "|null"), + " $", + name, + "\n", + ]); }); + this.emitBlock( + [ + "/**\n", + ...comments, + " */\n", + "public function __construct(", + ...args, + ")", + ], + () => { + this.forEachClassProperty(c, "none", (name) => { + this.emitLine("$this->", name, " = $", name, ";"); + }); + }, + ); let idx = 31; - this.forEachClassProperty(c, "leading-and-interposing", (name, jsonName, p) => { - const desc = this.descriptionForClassProperty(c, jsonName); - const names = defined(this._gettersAndSettersForPropertyName.get(name)); + this.forEachClassProperty( + c, + "leading-and-interposing", + (name, jsonName, p) => { + const desc = this.descriptionForClassProperty(c, jsonName); + const names = defined( + this._gettersAndSettersForPropertyName.get(name), + ); - this.ensureBlankLine(); - this.emitFromMethod(names, p, className, name, desc); - this.ensureBlankLine(); - this.emitToMethod(names, p, className, name, desc); - this.ensureBlankLine(); - this.emitValidateMethod(names, p, className, name, desc); - this.ensureBlankLine(); - this.emitGetMethod(names, p, className, name, desc); - this.ensureBlankLine(); - this.emitSetMethod(names, p, className, name, desc); - this.ensureBlankLine(); - this.emitSampleMethod(names, p, className, name, desc, idx++); - }); + this.ensureBlankLine(); + this.emitFromMethod(names, p, className, name, desc); + this.ensureBlankLine(); + this.emitToMethod(names, p, className, name, desc); + this.ensureBlankLine(); + this.emitValidateMethod(names, p, className, name, desc); + this.ensureBlankLine(); + this.emitGetMethod(names, p, className, name, desc); + this.ensureBlankLine(); + this.emitSetMethod(names, p, className, name, desc); + this.ensureBlankLine(); + this.emitSampleMethod( + names, + p, + className, + name, + desc, + idx++, + ); + }, + ); 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[][] = []; + const lines: Sourcelike[][] = []; let p = "return "; - this.forEachClassProperty(c, "none", (name, _jsonName, _p) => { - const names = defined(this._gettersAndSettersForPropertyName.get(name)); - lines.push([p, className, "::", names.validate, "($this->", name, ")"]); - p = "|| "; - }); + this.forEachClassProperty( + c, + "none", + (name, _jsonName, _p) => { + const names = defined( + this._gettersAndSettersForPropertyName.get( + name, + ), + ); + lines.push([ + p, + className, + "::", + names.validate, + "($this->", + name, + ")", + ]); + p = "|| "; + }, + ); lines.forEach((line, jdx) => { - this.emitLine(...line, lines.length === jdx + 1 ? ";" : ""); + this.emitLine( + ...line, + lines.length === jdx + 1 ? ";" : "", + ); }); - } + }, ); this.ensureBlankLine(); @@ -807,16 +1208,24 @@ 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();"); this.forEachClassProperty(c, "none", (name, jsonName) => { - const names = defined(this._gettersAndSettersForPropertyName.get(name)); - this.emitLine("$out->{'", jsonName, "'} = $this->", names.to, "();"); + const names = defined( + this._gettersAndSettersForPropertyName.get(name), + ); + this.emitLine( + "$out->{'", + jsonName, + "'} = $this->", + names.to, + "();", + ); }); this.emitLine("return $out;"); - } + }, ); this.ensureBlankLine(); @@ -830,39 +1239,76 @@ export class PhpRenderer extends ConvenienceRenderer { " * @throws Exception\n", " */\n", "public static function from(stdClass $obj): ", - className + className, ], () => { if (this._options.fastGet) { - this.forEachClassProperty(c, "none", name => { - const names = defined(this._gettersAndSettersForPropertyName.get(name)); - this.emitLine(className, "::", names.validate, "($this->", name, ", true);"); + this.forEachClassProperty(c, "none", (name) => { + const names = defined( + this._gettersAndSettersForPropertyName.get( + name, + ), + ); + this.emitLine( + className, + "::", + names.validate, + "($this->", + name, + ", true);", + ); }); } this.emitLine("return new ", className, "("); let comma = " "; this.forEachClassProperty(c, "none", (name, jsonName) => { - const names = defined(this._gettersAndSettersForPropertyName.get(name)); - this.emitLine(comma, className, "::", names.from, "($obj->{'", jsonName, "'})"); + const names = defined( + this._gettersAndSettersForPropertyName.get(name), + ); + this.emitLine( + comma, + className, + "::", + names.from, + "($obj->{'", + jsonName, + "'})", + ); comma = ","; }); this.emitLine(");"); - } + }, ); this.ensureBlankLine(); this.emitBlock( - ["/**\n", " * @return ", className, "\n", " */\n", "public static function sample(): ", className], + [ + "/**\n", + " * @return ", + className, + "\n", + " */\n", + "public static function sample(): ", + className, + ], () => { this.emitLine("return new ", className, "("); let comma = " "; - this.forEachClassProperty(c, "none", name => { - const names = defined(this._gettersAndSettersForPropertyName.get(name)); - this.emitLine(comma, className, "::", names.sample, "()"); + this.forEachClassProperty(c, "none", (name) => { + const names = defined( + this._gettersAndSettersForPropertyName.get(name), + ); + this.emitLine( + comma, + className, + "::", + names.sample, + "()", + ); comma = ","; }); this.emitLine(");"); - } + }, ); }); this.finishFile(); @@ -901,14 +1347,26 @@ export class PhpRenderer extends ConvenienceRenderer { this.emitBlock("public static function init()", () => { this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine(enumName, "::$", name, " = new ", enumName, "('", jsonName, "');"); + this.emitLine( + enumName, + "::$", + name, + " = new ", + enumName, + "('", + jsonName, + "');", + ); }); }); this.emitLine("private ", enumSerdeType, " $enum;"); - this.emitBlock(["public function __construct(", enumSerdeType, " $enum)"], () => { - this.emitLine("$this->enum = $enum;"); - }); + this.emitBlock( + ["public function __construct(", enumSerdeType, " $enum)"], + () => { + this.emitLine("$this->enum = $enum;"); + }, + ); this.ensureBlankLine(); this.emitEnumSerializationAttributes(e); @@ -927,7 +1385,7 @@ export class PhpRenderer extends ConvenienceRenderer { "public static function to(", enumName, " $obj): ", - enumSerdeType + enumSerdeType, ], () => { this.emitLine("switch ($obj->enum) {"); @@ -941,13 +1399,15 @@ 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.emitLine( + "throw new Exception('the give value is not an enum-value.');", + ); + }, ); this.ensureBlankLine(); this.emitEnumDeserializationAttributes(e); @@ -962,30 +1422,50 @@ export class PhpRenderer extends ConvenienceRenderer { " * @throws Exception\n", " */\n", "public static function from($obj): ", - enumName + enumName, ], () => { this.emitLine("switch ($obj) {"); this.indent(() => { this.forEachEnumCase(e, "none", (name, jsonName) => { // Todo String or Enum - this.emitLine("case '", stringEscape(jsonName), "': return ", enumName, "::$", name, ";"); + this.emitLine( + "case '", + stringEscape(jsonName), + "': return ", + enumName, + "::$", + name, + ";", + ); }); }); 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 => { + this.forEachEnumCase(e, "none", (name) => { lines.push([enumName, "::$", name]); }); this.emitLine("return ", lines[0], ";"); - } + }, ); }); this.emitLine(enumName, "::init();"); @@ -998,7 +1478,7 @@ export class PhpRenderer 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), ); if (this._options.withClosing) { this.emitLine("?>"); diff --git a/packages/quicktype-core/src/language/Php/language.ts b/packages/quicktype-core/src/language/Php/language.ts index f4860749..0e8aa7f1 100644 --- a/packages/quicktype-core/src/language/Php/language.ts +++ b/packages/quicktype-core/src/language/Php/language.ts @@ -1,10 +1,13 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { BooleanOption, getOptionValues } from "../../RendererOptions"; import { AcronymStyleOptions, acronymOption } from "../../support/Acronyms"; import { TargetLanguage } from "../../TargetLanguage"; -import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; -import { type StringTypeMapping } from "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } from "../../types"; import { PhpRenderer } from "./PhpRenderer"; @@ -13,16 +16,18 @@ 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 const phpLanguageConfig = { displayName: "PHP", names: ["php"], - extension: "php" + extension: "php", } as const; -export class PhpTargetLanguage extends TargetLanguage { +export class PhpTargetLanguage extends TargetLanguage< + typeof phpLanguageConfig +> { public constructor() { super(phpLanguageConfig); } @@ -35,13 +40,17 @@ export class PhpTargetLanguage extends TargetLanguage return true; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PhpRenderer { + protected makeRenderer( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): PhpRenderer { const options = getOptionValues(phpOptions, untypedOptionValues); return new PhpRenderer(this, renderContext, options); } public get stringTypeMapping(): StringTypeMapping { - const mapping: Map = new Map(); + 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 diff --git a/packages/quicktype-core/src/language/Php/utils.ts b/packages/quicktype-core/src/language/Php/utils.ts index 2ccb0e22..a235dc90 100644 --- a/packages/quicktype-core/src/language/Php/utils.ts +++ b/packages/quicktype-core/src/language/Php/utils.ts @@ -12,10 +12,12 @@ import { splitIntoWords, standardUnicodeHexEscape, utf16ConcatMap, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../../support/Strings"; -export const stringEscape = utf16ConcatMap(escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape)); +export const stringEscape = utf16ConcatMap( + escapeNonPrintableMapper(isAscii, standardUnicodeHexEscape), +); function isStartCharacter(codePoint: number): boolean { if (codePoint === 0x5f) return true; // underscore @@ -23,7 +25,10 @@ function isStartCharacter(codePoint: number): boolean { } function isPartCharacter(codePoint: number): boolean { - return isStartCharacter(codePoint) || (isAscii(codePoint) && isDigit(codePoint)); + return ( + isStartCharacter(codePoint) || + (isAscii(codePoint) && isDigit(codePoint)) + ); } const legalizeName = utf16LegalizeCharacters(isPartCharacter); @@ -32,17 +37,23 @@ 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( words, legalizeName, - upperUnderscore ? allUpperWordStyle : startWithUpper ? firstUpperWordStyle : allLowerWordStyle, + upperUnderscore + ? allUpperWordStyle + : startWithUpper + ? firstUpperWordStyle + : allLowerWordStyle, upperUnderscore ? allUpperWordStyle : firstUpperWordStyle, - upperUnderscore || startWithUpper ? allUpperWordStyle : allLowerWordStyle, + upperUnderscore || startWithUpper + ? allUpperWordStyle + : allLowerWordStyle, acronymsStyle, upperUnderscore ? "_" : "", - isStartCharacter + isStartCharacter, ); } diff --git a/packages/quicktype-core/src/language/Pike/PikeRenderer.ts b/packages/quicktype-core/src/language/Pike/PikeRenderer.ts index dca335b9..81fd8dda 100644 --- a/packages/quicktype-core/src/language/Pike/PikeRenderer.ts +++ b/packages/quicktype-core/src/language/Pike/PikeRenderer.ts @@ -1,6 +1,15 @@ -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; -import { type Name, type Namer } from "../../Naming"; -import { type MultiWord, type Sourcelike, multiWord, parenIfNeeded, singleWord } from "../../Source"; +import { + ConvenienceRenderer, + type ForbiddenWordsInfo, +} from "../../ConvenienceRenderer"; +import type { Name, Namer } from "../../Naming"; +import { + type MultiWord, + type Sourcelike, + multiWord, + parenIfNeeded, + singleWord, +} from "../../Source"; import { stringEscape } from "../../support/Strings"; import { ArrayType, @@ -9,12 +18,20 @@ import { MapType, PrimitiveType, type Type, - type UnionType + type UnionType, } from "../../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../Type/TypeUtils"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { enumNamingFunction, namedTypeNamingFunction, namingFunction } from "./utils"; +import { + enumNamingFunction, + namedTypeNamingFunction, + namingFunction, +} from "./utils"; export class PikeRenderer extends ConvenienceRenderer { protected emitSourceStructure(): void { @@ -28,14 +45,15 @@ 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), + (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), ); } @@ -63,15 +81,24 @@ export class PikeRenderer extends ConvenienceRenderer { 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 }; } @@ -82,30 +109,36 @@ export class PikeRenderer extends ConvenienceRenderer { return matchType( t, - _anyType => singleWord("mixed"), - _nullType => singleWord("mixed"), - _boolType => singleWord("bool"), - _integerType => singleWord("int"), - _doubleType => singleWord("float"), - _stringType => singleWord("string"), - arrayType => singleWord(["array(", this.sourceFor(arrayType.items).source, ")"]), - _classType => singleWord(this.nameForNamedType(_classType)), - mapType => { - let valueSource: Sourcelike; + (_anyType) => singleWord("mixed"), + (_nullType) => singleWord("mixed"), + (_boolType) => singleWord("bool"), + (_integerType) => singleWord("int"), + (_doubleType) => singleWord("float"), + (_stringType) => singleWord("string"), + (arrayType) => + singleWord([ + "array(", + this.sourceFor(arrayType.items).source, + ")", + ]), + (_classType) => singleWord(this.nameForNamedType(_classType)), + (mapType) => { const v = mapType.values; + const valueSource: Sourcelike = this.sourceFor(v).source; - valueSource = this.sourceFor(v).source; return singleWord(["mapping(string:", valueSource, ")"]); }, - _enumType => singleWord("enum"), - unionType => { + (_enumType) => singleWord("enum"), + (unionType) => { if (nullableFromUnion(unionType) !== null) { - const children = Array.from(unionType.getChildren()).map(c => parenIfNeeded(this.sourceFor(c))); + const children = Array.from(unionType.getChildren()).map( + (c) => parenIfNeeded(this.sourceFor(c)), + ); return multiWord("|", ...children); - } else { - return singleWord(this.nameForNamedType(unionType)); } - } + + return singleWord(this.nameForNamedType(unionType)); + }, ); } @@ -122,11 +155,11 @@ export class PikeRenderer extends ConvenienceRenderer { protected emitEnum(e: EnumType, enumName: Name): void { this.emitBlock([e.kind, " ", enumName], () => { - let table: Sourcelike[][] = []; + const table: Sourcelike[][] = []; this.forEachEnumCase(e, "none", (name, jsonName) => { table.push([ [name, ' = "', stringEscape(jsonName), '", '], - ['// json: "', jsonName, '"'] + ['// json: "', jsonName, '"'], ]); }); this.emitTable(table); @@ -144,7 +177,7 @@ export class PikeRenderer extends ConvenienceRenderer { const [, nonNulls] = removeNullFromUnion(u); - let types: Sourcelike[][] = []; + const types: Sourcelike[][] = []; this.forEachUnionMember(u, nonNulls, "none", null, (_name, t) => { const pikeType = this.sourceFor(t).source; types.push([pikeType]); @@ -152,18 +185,28 @@ export class PikeRenderer extends ConvenienceRenderer { this.emitLine([ "typedef ", - types.map(r => r.map(sl => this.sourcelikeToString(sl))).join("|"), + types + .map((r) => r.map((sl) => this.sourcelikeToString(sl))) + .join("|"), " ", unionName, - ";" + ";", ]); this.ensureBlankLine(); - this.emitBlock([unionName, " ", unionName, "_from_JSON(mixed json)"], () => { - this.emitLine(["return json;"]); - }); + this.emitBlock( + [unionName, " ", unionName, "_from_JSON(mixed json)"], + () => { + this.emitLine(["return json;"]); + }, + ); } - 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); @@ -174,14 +217,14 @@ export class PikeRenderer extends ConvenienceRenderer { } private emitClassMembers(c: ClassType): void { - let table: Sourcelike[][] = []; + const table: Sourcelike[][] = []; this.forEachClassProperty(c, "none", (name, jsonName, p) => { const pikeType = this.sourceFor(p.type).source; table.push([ [pikeType, " "], [name, "; "], - ['// json: "', jsonName, '"'] + ['// json: "', jsonName, '"'], ]); }); this.emitTable(table); @@ -202,9 +245,9 @@ 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: "// " }, ); } @@ -217,13 +260,20 @@ export class PikeRenderer extends ConvenienceRenderer { if (t instanceof PrimitiveType) { this.emitLine(["return json;"]); } else if (t instanceof ArrayType) { - if (t.items instanceof PrimitiveType) this.emitLine(["return json;"]); - else this.emitLine(["return map(json, ", this.sourceFor(t.items).source, "_from_JSON);"]); + if (t.items instanceof PrimitiveType) + this.emitLine(["return json;"]); + else + this.emitLine([ + "return map(json, ", + this.sourceFor(t.items).source, + "_from_JSON);", + ]); } else if (t instanceof MapType) { const type = this.sourceFor(t.values).source; this.emitLine(["mapping(string:", type, ") retval = ([]);"]); let assignmentRval: Sourcelike; - if (t.values instanceof PrimitiveType) assignmentRval = ["(", type, ") v"]; + if (t.values instanceof PrimitiveType) + assignmentRval = ["(", type, ") v"]; else assignmentRval = [type, "_from_JSON(v)"]; this.emitBlock(["foreach (json; string k; mixed v)"], () => { this.emitLine(["retval[k] = ", assignmentRval, ";"]); @@ -237,7 +287,13 @@ export class PikeRenderer extends ConvenienceRenderer { 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(); @@ -246,14 +302,23 @@ export class PikeRenderer extends ConvenienceRenderer { } private emitDecodingFunction(className: Name, c: ClassType): void { - 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.ensureBlankLine(); - this.emitLine(["return retval;"]); - }); + 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.ensureBlankLine(); + this.emitLine(["return retval;"]); + }, + ); } } diff --git a/packages/quicktype-core/src/language/Pike/constants.ts b/packages/quicktype-core/src/language/Pike/constants.ts index d3927948..c6a8024c 100644 --- a/packages/quicktype-core/src/language/Pike/constants.ts +++ b/packages/quicktype-core/src/language/Pike/constants.ts @@ -50,5 +50,5 @@ export const keywords = [ "sscanf", "switch", "typeof", - "global" + "global", ] as const; diff --git a/packages/quicktype-core/src/language/Pike/language.ts b/packages/quicktype-core/src/language/Pike/language.ts index 35be5b5a..cbce94b7 100644 --- a/packages/quicktype-core/src/language/Pike/language.ts +++ b/packages/quicktype-core/src/language/Pike/language.ts @@ -1,4 +1,4 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { TargetLanguage } from "../../TargetLanguage"; import { PikeRenderer } from "./PikeRenderer"; @@ -8,10 +8,12 @@ export const pikeOptions = {}; export const pikeLanguageConfig = { displayName: "Pike", names: ["pike", "pikelang"], - extension: "pmod" + extension: "pmod", } as const; -export class PikeTargetLanguage extends TargetLanguage { +export class PikeTargetLanguage extends TargetLanguage< + typeof pikeLanguageConfig +> { public constructor() { super(pikeLanguageConfig); } diff --git a/packages/quicktype-core/src/language/Pike/utils.ts b/packages/quicktype-core/src/language/Pike/utils.ts index f097ad2c..acd6a06e 100644 --- a/packages/quicktype-core/src/language/Pike/utils.ts +++ b/packages/quicktype-core/src/language/Pike/utils.ts @@ -1,7 +1,20 @@ import { funPrefixNamer } from "../../Naming"; -import { isLetterOrUnderscoreOrDigit, legalizeCharacters, makeNameStyle } from "../../support/Strings"; +import { + isLetterOrUnderscoreOrDigit, + legalizeCharacters, + 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)); +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), +); diff --git a/packages/quicktype-core/src/language/Python/JSONPythonRenderer.ts b/packages/quicktype-core/src/language/Python/JSONPythonRenderer.ts index 67c1e64b..b0696569 100644 --- a/packages/quicktype-core/src/language/Python/JSONPythonRenderer.ts +++ b/packages/quicktype-core/src/language/Python/JSONPythonRenderer.ts @@ -2,7 +2,13 @@ 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 { + type MultiWord, + type Sourcelike, + multiWord, + parenIfNeeded, + singleWord, +} from "../../Source"; import { assertNever, defined, panic } from "../../support/Support"; import { ChoiceTransformer, @@ -14,9 +20,9 @@ import { type Transformer, UnionInstantiationTransformer, UnionMemberMatchTransformer, - transformationForType + transformationForType, } from "../../Transformers"; -import { type ClassType, type Type } from "../../Type"; +import type { ClassType, Type } from "../../Type"; import { matchType } from "../../Type/TypeUtils"; import { PythonRenderer } from "./PythonRenderer"; @@ -60,11 +66,17 @@ 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: (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 { +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. @@ -73,11 +85,21 @@ function compose(input: ValueOrLambda, f: ValueOrLambda | ((arg: Sourcelike) => 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 }; + 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 }; + return { + lambda: multiWord(" ", "lambda x:", f("x")), + value: undefined, + }; } if (f.value !== undefined) { @@ -98,8 +120,15 @@ 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 + lambda: multiWord( + "", + "lambda x: ", + parenIfNeeded(f.lambda), + "(", + parenIfNeeded(input.lambda), + "(x))", + ), + value: undefined, }; } @@ -117,8 +146,16 @@ function makeLambda(vol: ValueOrLambda): MultiWord { return vol.lambda; } - return multiWord("", "lambda x: ", parenIfNeeded(vol.lambda), "(", vol.value, ")"); - } else if (vol.value !== undefined) { + return multiWord( + "", + "lambda x: ", + parenIfNeeded(vol.lambda), + "(", + vol.value, + ")", + ); + } + if (vol.value !== undefined) { return multiWord(" ", "lambda x:", vol.value); } @@ -142,11 +179,14 @@ function makeValue(vol: ValueOrLambda): Sourcelike { export class JSONPythonRenderer extends PythonRenderer { private readonly _deserializerFunctions = new Set(); - private readonly _converterNamer = funPrefixNamer("converter", s => - snakeNameStyle(s, false, this.pyOptions.nicePropertyNames) + private readonly _converterNamer = funPrefixNamer("converter", (s) => + snakeNameStyle(s, false, this.pyOptions.nicePropertyNames), ); - private readonly _topLevelConverterNames = new Map(); + private readonly _topLevelConverterNames = new Map< + Name, + TopLevelConverterNames + >(); private _haveTypeVar = false; @@ -159,7 +199,15 @@ export class JSONPythonRenderer extends PythonRenderer { return; } - this.emitLine(tvar, " = ", this.withTyping("TypeVar"), "(", this.string(tvar), constraints, ")"); + this.emitLine( + tvar, + " = ", + this.withTyping("TypeVar"), + "(", + this.string(tvar), + constraints, + ")", + ); } protected typeVar(): string { @@ -194,48 +242,103 @@ export class JSONPythonRenderer extends PythonRenderer { // 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( - ["def from_none(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withTyping("Any")), ":"], + [ + "def from_none(", + this.typingDecl("x", "Any"), + ")", + this.typeHint(" -> ", this.withTyping("Any")), + ":", + ], () => { this.emitLine("assert x is None"); this.emitLine("return x"); - } + }, ); } 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"); - }); + 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 { - 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"); - }); + 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 { - 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)"); - }); + 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 { - this.emitBlock(["def to_float(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> float"), ":"], () => { - this.emitLine("assert isinstance(x, (int, float))"); - this.emitLine("return x"); - }); + this.emitBlock( + [ + "def to_float(", + this.typingDecl("x", "Any"), + ")", + this.typeHint(" -> float"), + ":", + ], + () => { + this.emitLine("assert isinstance(x, (int, float))"); + this.emitLine("return x"); + }, + ); } protected emitStrConverter(): void { - this.emitBlock(["def from_str(", this.typingDecl("x", "Any"), ")", this.typeHint(" -> str"), ":"], () => { - const strType = "str"; - this.emitLine("assert isinstance(x, ", strType, ")"); - this.emitLine("return x"); - }); + this.emitBlock( + [ + "def from_str(", + this.typingDecl("x", "Any"), + ")", + this.typeHint(" -> str"), + ":", + ], + () => { + const strType = "str"; + this.emitLine("assert isinstance(x, ", strType, ")"); + this.emitLine("return x"); + }, + ); } protected emitToEnumConverter(): void { @@ -248,12 +351,12 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", tvar), - ":" + ":", ], () => { this.emitLine("assert isinstance(x, c)"); this.emitLine("return x.value"); - } + }, ); } @@ -262,17 +365,25 @@ export class JSONPythonRenderer extends PythonRenderer { this.emitBlock( [ "def from_list(f", - this.typeHint(": ", this.withTyping("Callable"), "[[", this.withTyping("Any"), "], ", tvar, "]"), + this.typeHint( + ": ", + this.withTyping("Callable"), + "[[", + this.withTyping("Any"), + "], ", + tvar, + "]", + ), ", ", 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]"); - } + }, ); } @@ -286,12 +397,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()"); - } + this.emitLine( + "return ", + this.cast(this.withTyping("Any"), "x"), + ".to_dict()", + ); + }, ); } @@ -300,17 +415,31 @@ export class JSONPythonRenderer extends PythonRenderer { this.emitBlock( [ "def from_dict(f", - this.typeHint(": ", this.withTyping("Callable"), "[[", this.withTyping("Any"), "], ", tvar, "]"), + this.typeHint( + ": ", + this.withTyping("Callable"), + "[[", + this.withTyping("Any"), + "], ", + tvar, + "]", + ), ", ", this.typingDecl("x", "Any"), ")", - this.typeHint(" -> ", this.withTyping("Dict"), "[str, ", tvar, "]"), - ":" + 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() }"); - } + }, ); } @@ -333,23 +462,33 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", this.withImport("datetime", "datetime")), - ":" + ":", ], () => { this._haveDateutil = true; this.emitLine("return dateutil.parser.parse(x)"); - } + }, ); } protected emitFromStringifiedBoolConverter(): void { this.emitBlock( - ["def from_stringified_bool(x", this.typeHint(": str"), ")", this.typeHint(" -> bool"), ":"], + [ + "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"); - } + }, ); } @@ -363,12 +502,12 @@ export class JSONPythonRenderer extends PythonRenderer { this.typingDecl("x", "Any"), ")", this.typeHint(" -> ", tvar), - ":" + ":", ], () => { this.emitLine("assert isinstance(x, t)"); this.emitLine("return x"); - } + }, ); } @@ -445,7 +584,7 @@ export class JSONPythonRenderer extends PythonRenderer { } default: - return assertNever(cf); + assertNever(cf); } } @@ -453,30 +592,38 @@ export class JSONPythonRenderer extends PythonRenderer { 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; + if ( + cf.startsWith("from-") || + cf.startsWith("to-") || + cf.startsWith("is-") + ) + return name; return ["from_", name]; } // Applies the converter function to `arg` protected convFn(cf: ConverterFunction, arg: ValueOrLambda): ValueOrLambda { - return compose(arg, { lambda: singleWord(this.conv(cf)), value: undefined }); + return compose(arg, { + lambda: singleWord(this.conv(cf)), + value: undefined, + }); } protected typeObject(t: Type): Sourcelike { const s = matchType( t, - _anyType => undefined, - _nullType => "type(None)", - _boolType => "bool", - _integerType => "int", - _doubleType => "float", - _stringType => "str", - _arrayType => "List", - classType => this.nameForNamedType(classType), - _mapType => "dict", - enumType => this.nameForNamedType(enumType), - _unionType => undefined, - transformedStringType => { + (_anyType) => undefined, + (_nullType) => "type(None)", + (_boolType) => "bool", + (_integerType) => "int", + (_doubleType) => "float", + (_stringType) => "str", + (_arrayType) => "List", + (classType) => this.nameForNamedType(classType), + (_mapType) => "dict", + (enumType) => this.nameForNamedType(enumType), + (_unionType) => undefined, + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return this.withImport("datetime", "datetime"); } @@ -486,7 +633,7 @@ export class JSONPythonRenderer extends PythonRenderer { } return undefined; - } + }, ); if (s === undefined) { return panic(`No type object for ${t.kind}`); @@ -495,8 +642,15 @@ export class JSONPythonRenderer extends PythonRenderer { return s; } - protected transformer(inputTransformer: ValueOrLambda, xfer: Transformer, targetType: Type): ValueOrLambda { - const consume = (consumer: Transformer | undefined, vol: ValueOrLambda): ValueOrLambda => { + protected transformer( + inputTransformer: ValueOrLambda, + xfer: Transformer, + targetType: Type, + ): ValueOrLambda { + const consume = ( + consumer: Transformer | undefined, + vol: ValueOrLambda, + ): ValueOrLambda => { if (consumer === undefined) { return vol; } @@ -504,84 +658,127 @@ export class JSONPythonRenderer extends PythonRenderer { return this.transformer(vol, consumer, targetType); }; - const isType = (t: Type, valueToCheck: ValueOrLambda): ValueOrLambda => { - return compose(valueToCheck, v => [this.conv("is-type"), "(", this.typeObject(t), ", ", v, ")"]); + const isType = ( + t: Type, + valueToCheck: ValueOrLambda, + ): ValueOrLambda => { + return compose(valueToCheck, (v) => [ + this.conv("is-type"), + "(", + this.typeObject(t), + ", ", + v, + ")", + ]); }; - if (xfer instanceof DecodingChoiceTransformer || xfer instanceof ChoiceTransformer) { - const lambdas = xfer.transformers.map(x => makeLambda(this.transformer(identity, x, targetType)).source); - return compose(inputTransformer, v => [ + if ( + xfer instanceof DecodingChoiceTransformer || + xfer instanceof ChoiceTransformer + ) { + const lambdas = xfer.transformers.map( + (x) => + makeLambda(this.transformer(identity, x, targetType)) + .source, + ); + return compose(inputTransformer, (v) => [ this.conv("union"), "([", arrayIntercalate(", ", lambdas), "], ", v, - ")" + ")", ]); - } else if (xfer instanceof DecodingTransformer) { + } + if (xfer instanceof DecodingTransformer) { const consumer = xfer.consumer; const vol = this.deserializer(inputTransformer, xfer.sourceType); return consume(consumer, vol); - } else if (xfer instanceof EncodingTransformer) { + } + if (xfer instanceof EncodingTransformer) { return this.serializer(inputTransformer, xfer.sourceType); - } else if (xfer instanceof UnionInstantiationTransformer) { + } + if (xfer instanceof UnionInstantiationTransformer) { return inputTransformer; - } else if (xfer instanceof UnionMemberMatchTransformer) { + } + if (xfer instanceof UnionMemberMatchTransformer) { const consumer = xfer.transformer; const vol = isType(xfer.memberType, inputTransformer); return consume(consumer, vol); - } else if (xfer instanceof ParseStringTransformer) { + } + if (xfer instanceof ParseStringTransformer) { const consumer = xfer.consumer; - const immediateTargetType = consumer === undefined ? targetType : consumer.sourceType; + const immediateTargetType = + consumer === undefined ? targetType : consumer.sourceType; let vol: ValueOrLambda; switch (immediateTargetType.kind) { case "integer": - vol = compose(inputTransformer, v => ["int(", v, ")"]); + vol = compose(inputTransformer, (v) => ["int(", v, ")"]); break; case "bool": - vol = this.convFn("from-stringified-bool", inputTransformer); + vol = this.convFn( + "from-stringified-bool", + inputTransformer, + ); break; case "enum": - vol = this.deserializer(inputTransformer, immediateTargetType); + vol = this.deserializer( + inputTransformer, + immediateTargetType, + ); break; case "date-time": vol = this.convFn("from-datetime", inputTransformer); break; case "uuid": - vol = compose(inputTransformer, v => [this.withImport("uuid", "UUID"), "(", v, ")"]); + vol = compose(inputTransformer, (v) => [ + this.withImport("uuid", "UUID"), + "(", + v, + ")", + ]); break; default: - return panic(`Parsing of ${immediateTargetType.kind} in a transformer is not supported`); + return panic( + `Parsing of ${immediateTargetType.kind} in a transformer is not supported`, + ); } return consume(consumer, vol); - } else if (xfer instanceof StringifyTransformer) { + } + if (xfer instanceof StringifyTransformer) { const consumer = xfer.consumer; let vol: ValueOrLambda; switch (xfer.sourceType.kind) { case "integer": - vol = compose(inputTransformer, v => ["str(", v, ")"]); + vol = compose(inputTransformer, (v) => ["str(", v, ")"]); break; case "bool": - vol = compose(inputTransformer, v => ["str(", v, ").lower()"]); + vol = compose(inputTransformer, (v) => [ + "str(", + v, + ").lower()", + ]); break; case "enum": vol = this.serializer(inputTransformer, xfer.sourceType); break; case "date-time": - vol = compose(inputTransformer, v => [v, ".isoformat()"]); + vol = compose(inputTransformer, (v) => [v, ".isoformat()"]); break; case "uuid": - vol = compose(inputTransformer, v => ["str(", v, ")"]); + vol = compose(inputTransformer, (v) => ["str(", v, ")"]); break; default: - return panic(`Parsing of ${xfer.sourceType.kind} in a transformer is not supported`); + 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`); } + + return panic(`Transformer ${xfer.kind} is not supported`); } // Returns the code to deserialize `value` as type `t`. If `t` has @@ -595,62 +792,78 @@ export class JSONPythonRenderer extends PythonRenderer { return matchType( t, - _anyType => value, - _nullType => this.convFn("none", value), - _boolType => this.convFn("bool", value), - _integerType => this.convFn("int", value), - _doubleType => this.convFn("from-float", value), - _stringType => this.convFn("str", value), - arrayType => - compose(value, v => [ + (_anyType) => value, + (_nullType) => this.convFn("none", value), + (_boolType) => this.convFn("bool", value), + (_integerType) => this.convFn("int", value), + (_doubleType) => this.convFn("from-float", value), + (_stringType) => this.convFn("str", value), + (arrayType) => + compose(value, (v) => [ this.conv("list"), "(", - makeLambda(this.deserializer(identity, arrayType.items)).source, + makeLambda(this.deserializer(identity, arrayType.items)) + .source, ", ", v, - ")" + ")", ]), - classType => + (classType) => compose(value, { - lambda: singleWord(this.nameForNamedType(classType), ".from_dict"), - value: undefined + lambda: singleWord( + this.nameForNamedType(classType), + ".from_dict", + ), + value: undefined, }), - mapType => - compose(value, v => [ + (mapType) => + compose(value, (v) => [ this.conv("dict"), "(", - makeLambda(this.deserializer(identity, mapType.values)).source, + makeLambda(this.deserializer(identity, mapType.values)) + .source, ", ", v, - ")" + ")", ]), - enumType => compose(value, { lambda: singleWord(this.nameForNamedType(enumType)), value: undefined }), - unionType => { + (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 => [ + return compose(value, (v) => [ this.conv("union"), "([", arrayIntercalate(", ", deserializers), "], ", v, - ")" + ")", ]); }, - transformedStringType => { + (transformedStringType) => { // FIXME: handle via transformers 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 compose(value, (v) => [ + this.withImport("uuid", "UUID"), + "(", + v, + ")", + ]); } - return panic(`Transformed type ${transformedStringType.kind} not supported`); - } + return panic( + `Transformed type ${transformedStringType.kind} not supported`, + ); + }, ); } @@ -658,62 +871,85 @@ export class JSONPythonRenderer extends PythonRenderer { const xf = transformationForType(t); if (xf !== undefined) { const reverse = xf.reverse; - return this.transformer(value, reverse.transformer, reverse.targetType); + return this.transformer( + value, + reverse.transformer, + reverse.targetType, + ); } return matchType( t, - _anyType => value, - _nullType => this.convFn("none", value), - _boolType => this.convFn("bool", value), - _integerType => this.convFn("int", value), - _doubleType => this.convFn("to-float", value), - _stringType => this.convFn("str", value), - arrayType => - compose(value, v => [ + (_anyType) => value, + (_nullType) => this.convFn("none", value), + (_boolType) => this.convFn("bool", value), + (_integerType) => this.convFn("int", value), + (_doubleType) => this.convFn("to-float", value), + (_stringType) => this.convFn("str", value), + (arrayType) => + compose(value, (v) => [ this.conv("list"), "(", - makeLambda(this.serializer(identity, arrayType.items)).source, + makeLambda(this.serializer(identity, arrayType.items)) + .source, ", ", v, - ")" + ")", ]), - classType => - compose(value, v => [this.conv("to-class"), "(", this.nameForNamedType(classType), ", ", v, ")"]), - mapType => - compose(value, v => [ + (classType) => + compose(value, (v) => [ + this.conv("to-class"), + "(", + this.nameForNamedType(classType), + ", ", + v, + ")", + ]), + (mapType) => + compose(value, (v) => [ this.conv("dict"), "(", - makeLambda(this.serializer(identity, mapType.values)).source, + makeLambda(this.serializer(identity, mapType.values)) + .source, ", ", v, - ")" + ")", ]), - enumType => compose(value, v => [this.conv("to-enum"), "(", this.nameForNamedType(enumType), ", ", v, ")"]), - unionType => { + (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 => [ + return compose(value, (v) => [ this.conv("union"), "([", arrayIntercalate(", ", serializers), "], ", v, - ")" + ")", ]); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { - return compose(value, v => [v, ".isoformat()"]); + return compose(value, (v) => [v, ".isoformat()"]); } if (transformedStringType.kind === "uuid") { - return compose(value, v => ["str(", v, ")"]); + return compose(value, (v) => ["str(", v, ")"]); } - return panic(`Transformed type ${transformedStringType.kind} not supported`); - } + return panic( + `Transformed type ${transformedStringType.kind} not supported`, + ); + }, ); } @@ -725,44 +961,70 @@ export class JSONPythonRenderer extends PythonRenderer { this.emitLine("@staticmethod"); this.emitBlock( - ["def from_dict(", this.typingDecl("obj", "Any"), ")", this.typeHint(" -> ", this.namedType(t)), ":"], + [ + "def from_dict(", + this.typingDecl("obj", "Any"), + ")", + this.typeHint(" -> ", this.namedType(t)), + ":", + ], () => { const args: Sourcelike[] = []; this.emitLine("assert isinstance(obj, dict)"); this.forEachClassProperty(t, "none", (name, jsonName, cp) => { - const property = { value: ["obj.get(", this.string(jsonName), ")"] }; - this.emitLine(name, " = ", makeValue(this.deserializer(property, cp.type))); + const property = { + value: ["obj.get(", this.string(jsonName), ")"], + }; + this.emitLine( + name, + " = ", + makeValue(this.deserializer(property, cp.type)), + ); args.push(name); }); - this.emitLine("return ", className, "(", arrayIntercalate(", ", args), ")"); - } + this.emitLine( + "return ", + className, + "(", + arrayIntercalate(", ", args), + ")", + ); + }, ); this.ensureBlankLine(); - this.emitBlock(["def to_dict(self)", this.typeHint(" -> dict"), ":"], () => { - this.emitLine("result", this.typeHint(": dict"), " = {}"); - this.forEachClassProperty(t, "none", (name, jsonName, cp) => { - const property = { value: ["self.", name] }; - if (cp.isOptional) { - this.emitBlock(["if self.", name, " is not None:"], () => { + this.emitBlock( + ["def to_dict(self)", this.typeHint(" -> dict"), ":"], + () => { + this.emitLine("result", this.typeHint(": dict"), " = {}"); + this.forEachClassProperty(t, "none", (name, jsonName, cp) => { + const property = { value: ["self.", name] }; + if (cp.isOptional) { + this.emitBlock( + ["if self.", name, " is not None:"], + () => { + this.emitLine( + "result[", + this.string(jsonName), + "] = ", + makeValue( + this.serializer(property, cp.type), + ), + ); + }, + ); + } else { this.emitLine( "result[", this.string(jsonName), "] = ", - makeValue(this.serializer(property, cp.type)) + makeValue(this.serializer(property, cp.type)), ); - }); - } else { - this.emitLine( - "result[", - this.string(jsonName), - "] = ", - makeValue(this.serializer(property, cp.type)) - ); - } - }); - this.emitLine("return result"); - }); + } + }); + this.emitLine("return result"); + }, + ); } protected emitImports(): void { @@ -779,24 +1041,36 @@ export class JSONPythonRenderer extends PythonRenderer { } if (this._haveEnumTypeVar) { - this.emitTypeVar(this.enumTypeVar(), [", bound=", this.withImport("enum", "Enum")]); + this.emitTypeVar(this.enumTypeVar(), [ + ", bound=", + this.withImport("enum", "Enum"), + ]); } } protected emitSupportCode(): void { - const map = Array.from(this._deserializerFunctions).map(f => [f, f] as [ConverterFunction, ConverterFunction]); - this.forEachWithBlankLines(map, ["interposing", 2], cf => { + 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`, ); - const toDict = new DependencyName(this._converterNamer, topLevelNameOrder, l => `${l(topLevelName)}_to_dict`); this._topLevelConverterNames.set(topLevelName, { fromDict, toDict }); return [fromDict, toDict]; } @@ -808,7 +1082,7 @@ export class JSONPythonRenderer extends PythonRenderer { "This code parses date/times, so please", "", " pip install python-dateutil", - "" + "", ]); } @@ -818,30 +1092,61 @@ 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)); - this.emitLine(this.commentLineStart, " result = ", fromDict, "(json.loads(json_string))"); + const { fromDict } = defined( + this._topLevelConverterNames.get(name), + ); + this.emitLine( + this.commentLineStart, + " result = ", + fromDict, + "(json.loads(json_string))", + ); }); } protected emitClosingCode(): void { this.forEachTopLevel(["interposing", 2], (t, name) => { - const { fromDict, toDict } = defined(this._topLevelConverterNames.get(name)); + const { fromDict, toDict } = defined( + this._topLevelConverterNames.get(name), + ); const pythonType = this.pythonType(t); this.emitBlock( - ["def ", fromDict, "(", this.typingDecl("s", "Any"), ")", this.typeHint(" -> ", pythonType), ":"], + [ + "def ", + fromDict, + "(", + this.typingDecl("s", "Any"), + ")", + this.typeHint(" -> ", pythonType), + ":", + ], () => { - this.emitLine("return ", makeValue(this.deserializer({ value: "s" }, t))); - } + this.emitLine( + "return ", + makeValue(this.deserializer({ value: "s" }, t)), + ); + }, ); this.ensureBlankLine(2); this.emitBlock( - ["def ", toDict, "(x", this.typeHint(": ", pythonType), ")", this.typingReturn("Any"), ":"], + [ + "def ", + toDict, + "(x", + this.typeHint(": ", pythonType), + ")", + this.typingReturn("Any"), + ":", + ], () => { - this.emitLine("return ", makeValue(this.serializer({ value: "x" }, t))); - } + this.emitLine( + "return ", + makeValue(this.serializer({ value: "x" }, t)), + ); + }, ); }); } diff --git a/packages/quicktype-core/src/language/Python/PythonRenderer.ts b/packages/quicktype-core/src/language/Python/PythonRenderer.ts index 0e17b49b..fd7bb84e 100644 --- a/packages/quicktype-core/src/language/Python/PythonRenderer.ts +++ b/packages/quicktype-core/src/language/Python/PythonRenderer.ts @@ -1,19 +1,38 @@ -import { arrayIntercalate, iterableFirst, mapSortBy, mapUpdateInto, setUnionInto } from "collection-utils"; +import { + arrayIntercalate, + iterableFirst, + mapSortBy, + mapUpdateInto, + setUnionInto, +} from "collection-utils"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +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 { 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 type { TargetLanguage } from "../../TargetLanguage"; import { followTargetType } from "../../Transformers"; -import { type ClassProperty, ClassType, EnumType, type Type, UnionType } from "../../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../Type/TypeUtils"; +import { + type ClassProperty, + ClassType, + EnumType, + type Type, + UnionType, +} from "../../Type"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { forbiddenPropertyNames, forbiddenTypeNames } from "./constants"; -import { type pythonOptions } from "./language"; +import type { pythonOptions } from "./language"; import { classNameStyle, snakeNameStyle } from "./utils"; export class PythonRenderer extends ConvenienceRenderer { @@ -24,7 +43,7 @@ export class PythonRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly pyOptions: OptionValues + protected readonly pyOptions: OptionValues, ) { super(targetLanguage, renderContext); } @@ -33,8 +52,14 @@ export class PythonRenderer extends ConvenienceRenderer { return forbiddenTypeNames; } - protected forbiddenForObjectProperties(_: ClassType, _classNamed: Name): ForbiddenWordsInfo { - return { names: forbiddenPropertyNames as unknown as string[], includeGlobalForbidden: false }; + protected forbiddenForObjectProperties( + _: ClassType, + _classNamed: Name, + ): ForbiddenWordsInfo { + return { + names: forbiddenPropertyNames as unknown as string[], + includeGlobalForbidden: false, + }; } protected makeNamedTypeNamer(): Namer { @@ -42,7 +67,9 @@ export class PythonRenderer extends ConvenienceRenderer { } protected namerForObjectProperty(): Namer { - return funPrefixNamer("property", s => snakeNameStyle(s, false, this.pyOptions.nicePropertyNames)); + return funPrefixNamer("property", (s) => + snakeNameStyle(s, false, this.pyOptions.nicePropertyNames), + ); } protected makeUnionMemberNamer(): null { @@ -50,7 +77,9 @@ export class PythonRenderer extends ConvenienceRenderer { } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enum-case", s => snakeNameStyle(s, true, this.pyOptions.nicePropertyNames)); + return funPrefixNamer("enum-case", (s) => + snakeNameStyle(s, true, this.pyOptions.nicePropertyNames), + ); } protected get commentLineStart(): string { @@ -59,19 +88,21 @@ export class PythonRenderer extends ConvenienceRenderer { protected emitDescriptionBlock(lines: Sourcelike[]): void { if (lines.length === 1) { - const docstring = modifySource(content => { + const docstring = modifySource((content) => { 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: '"""', lineStart: "", - afterComment: '"""' + afterComment: '"""', }); } } @@ -101,7 +132,9 @@ export class PythonRenderer extends ConvenienceRenderer { // 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; @@ -122,25 +155,38 @@ export class PythonRenderer extends ConvenienceRenderer { 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 => { + (_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)); + const memberTypes = Array.from(nonNulls).map((m) => + this.pythonType(m), + ); if (hasNull !== null) { - let rest: string[] = []; + const rest: string[] = []; if ( !this.getAlphabetizeProperties() && - (this.pyOptions.features.dataClasses || this.pyOptions.pydanticBaseModel) && + (this.pyOptions.features.dataClasses || + this.pyOptions.pydanticBaseModel) && _isRootTypeDef ) { // Only push "= None" if this is a root level type def @@ -156,16 +202,27 @@ export class PythonRenderer extends ConvenienceRenderer { "[Union[", arrayIntercalate(", ", memberTypes), "]]", - ...rest + ...rest, ]; - } else { - return [this.withTyping("Optional"), "[", defined(iterableFirst(memberTypes)), "]", ...rest]; } - } else { - return [this.withTyping("Union"), "[", arrayIntercalate(", ", memberTypes), "]"]; + + return [ + this.withTyping("Optional"), + "[", + defined(iterableFirst(memberTypes)), + "]", + ...rest, + ]; } + + return [ + this.withTyping("Union"), + "[", + arrayIntercalate(", ", memberTypes), + "]", + ]; }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return this.withImport("datetime", "datetime"); } @@ -174,21 +231,35 @@ export class PythonRenderer extends ConvenienceRenderer { return this.withImport("uuid", "UUID"); } - return panic(`Transformed type ${transformedStringType.kind} not supported`); - } + return panic( + `Transformed type ${transformedStringType.kind} not supported`, + ); + }, ); } protected declarationLine(t: Type): Sourcelike { if (t instanceof ClassType) { if (this.pyOptions.pydanticBaseModel) { - return ["class ", this.nameForNamedType(t), "(", this.withImport("pydantic", "BaseModel"), "):"]; + return [ + "class ", + this.nameForNamedType(t), + "(", + this.withImport("pydantic", "BaseModel"), + "):", + ]; } return ["class ", this.nameForNamedType(t), ":"]; } if (t instanceof EnumType) { - return ["class ", this.nameForNamedType(t), "(", this.withImport("enum", "Enum"), "):"]; + return [ + "class ", + this.nameForNamedType(t), + "(", + this.withImport("enum", "Enum"), + "):", + ]; } return panic(`Can't declare type ${t.kind}`); @@ -203,23 +274,33 @@ export class PythonRenderer extends ConvenienceRenderer { } protected emitClassMembers(t: ClassType): void { - if (this.pyOptions.features.dataClasses || this.pyOptions.pydanticBaseModel) return; + if ( + this.pyOptions.features.dataClasses || + this.pyOptions.pydanticBaseModel + ) + 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"), ":"], + [ + "def __init__(self, ", + arrayIntercalate(", ", args), + ")", + this.typeHint(" -> None"), + ":", + ], () => { if (args.length === 0) { this.emitLine("pass"); } else { - this.forEachClassProperty(t, "none", name => { + this.forEachClassProperty(t, "none", (name) => { this.emitLine("self.", name, " = ", name); }); } - } + }, ); } @@ -241,19 +322,29 @@ export class PythonRenderer extends ConvenienceRenderer { protected sortClassProperties( properties: ReadonlyMap, - propertyNames: ReadonlyMap + propertyNames: ReadonlyMap, ): ReadonlyMap { - if (this.pyOptions.features.dataClasses || this.pyOptions.pydanticBaseModel) { + if ( + this.pyOptions.features.dataClasses || + this.pyOptions.pydanticBaseModel + ) { 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); } + + return super.sortClassProperties(properties, propertyNames); } protected emitClass(t: ClassType): void { - if (this.pyOptions.features.dataClasses && !this.pyOptions.pydanticBaseModel) { + if ( + this.pyOptions.features.dataClasses && + !this.pyOptions.pydanticBaseModel + ) { this.emitLine("@", this.withImport("dataclasses", "dataclass")); } @@ -262,10 +353,22 @@ export class PythonRenderer extends ConvenienceRenderer { 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.forEachClassProperty( + t, + "none", + (name, jsonName, cp) => { + this.emitLine( + name, + this.typeHint( + ": ", + this.pythonType(cp.type, true), + ), + ); + this.emitDescription( + this.descriptionForClassProperty(t, jsonName), + ); + }, + ); } this.ensureBlankLine(); @@ -285,7 +388,12 @@ export class PythonRenderer extends ConvenienceRenderer { protected emitImports(): void { this.imports.forEach((names, module) => { - this.emitLine("from ", module, " import ", Array.from(names).join(", ")); + this.emitLine( + "from ", + module, + " import ", + Array.from(names).join(", "), + ); }); } @@ -302,10 +410,10 @@ export class PythonRenderer extends ConvenienceRenderer { this.forEachNamedType( ["interposing", 2], (c: ClassType) => this.emitClass(c), - e => this.emitEnum(e), - _u => { + (e) => this.emitEnum(e), + (_u) => { return; - } + }, ); }); diff --git a/packages/quicktype-core/src/language/Python/constants.ts b/packages/quicktype-core/src/language/Python/constants.ts index 0e725bf5..d32c1092 100644 --- a/packages/quicktype-core/src/language/Python/constants.ts +++ b/packages/quicktype-core/src/language/Python/constants.ts @@ -12,7 +12,7 @@ export const forbiddenTypeNames = [ "Type", "TypeVar", "T", - "EnumT" + "EnumT", ] as const; export const forbiddenPropertyNames = [ @@ -55,5 +55,5 @@ export const forbiddenPropertyNames = [ "try", "while", "with", - "yield" + "yield", ] as const; diff --git a/packages/quicktype-core/src/language/Python/language.ts b/packages/quicktype-core/src/language/Python/language.ts index 6a444c07..c6a35b0d 100644 --- a/packages/quicktype-core/src/language/Python/language.ts +++ b/packages/quicktype-core/src/language/Python/language.ts @@ -1,11 +1,20 @@ import { iterableSome } from "collection-utils"; -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type PrimitiveStringTypeKind, type TransformedStringTypeKind, type Type, UnionType } from "../../Type"; -import { type StringTypeMapping } from "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import { + type PrimitiveStringTypeKind, + type TransformedStringTypeKind, + type Type, + UnionType, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } from "../../types"; import { JSONPythonRenderer } from "./JSONPythonRenderer"; import { PythonRenderer } from "./PythonRenderer"; @@ -22,18 +31,32 @@ 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), - pydanticBaseModel: new BooleanOption("pydantic-base-model", "Uses pydantic BaseModel", false) + nicePropertyNames: new BooleanOption( + "nice-property-names", + "Transform property names to be Pythonic", + true, + ), + pydanticBaseModel: new BooleanOption( + "pydantic-base-model", + "Uses pydantic BaseModel", + false, + ), }; -export const pythonLanguageConfig = { displayName: "Python", names: ["python", "py"], extension: "py" } as const; +export const pythonLanguageConfig = { + displayName: "Python", + names: ["python", "py"], + extension: "py", +} as const; -export class PythonTargetLanguage extends TargetLanguage { +export class PythonTargetLanguage extends TargetLanguage< + typeof pythonLanguageConfig +> { public constructor() { super(pythonLanguageConfig); } @@ -43,7 +66,8 @@ export class PythonTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); mapping.set("time", dateTimeType); @@ -64,18 +88,23 @@ export class PythonTargetLanguage extends TargetLanguage this.needsTransformerForType(m)); + return iterableSome(t.members, (m) => + this.needsTransformerForType(m), + ); } return t.kind === "integer-string" || t.kind === "bool-string"; } - protected makeRenderer(renderContext: RenderContext, untypedOptionValues: FixMeOptionsType): PythonRenderer { + protected makeRenderer( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): PythonRenderer { const options = getOptionValues(pythonOptions, untypedOptionValues); if (options.justTypes) { return new PythonRenderer(this, renderContext, options); - } else { - return new JSONPythonRenderer(this, renderContext, options); } + + 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 index 6ffb8c5a..e39a9c7e 100644 --- a/packages/quicktype-core/src/language/Python/utils.ts +++ b/packages/quicktype-core/src/language/Python/utils.ts @@ -7,7 +7,7 @@ import { firstUpperWordStyle, originalWord, splitIntoWords, - utf16LegalizeCharacters + utf16LegalizeCharacters, } from "../../support/Strings"; function isNormalizedStartCharacter3(utf16Unit: number): boolean { @@ -56,7 +56,7 @@ export function classNameStyle(original: string): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter3 + isStartCharacter3, ); } @@ -68,9 +68,22 @@ function getWordStyle(uppercase: boolean, forceSnakeNameStyle: boolean) { return uppercase ? allUpperWordStyle : allLowerWordStyle; } -export function snakeNameStyle(original: string, uppercase: boolean, forceSnakeNameStyle: boolean): string { +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); + return combineWords( + words, + legalizeName3, + wordStyle, + wordStyle, + wordStyle, + wordStyle, + separator, + isStartCharacter3, + ); } diff --git a/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts index 224b4ddb..af5af4b6 100644 --- a/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts +++ b/packages/quicktype-core/src/language/Ruby/RubyRenderer.ts @@ -1,10 +1,13 @@ -import { ConvenienceRenderer, type ForbiddenWordsInfo } from "../../ConvenienceRenderer"; +import { + ConvenienceRenderer, + type ForbiddenWordsInfo, +} from "../../ConvenienceRenderer"; import { type Name, Namer } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { type OptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; import { type Sourcelike, modifySource } from "../../Source"; import { snakeCase } from "../../support/Strings"; -import { type TargetLanguage } from "../../TargetLanguage"; +import type { TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, @@ -12,19 +15,29 @@ import { type EnumType, MapType, type Type, - type UnionType + type UnionType, } from "../../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../Type/TypeUtils"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { globals } from "./constants"; -import { type rubyOptions } from "./language"; -import { Strictness, 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( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -42,15 +55,28 @@ export class RubyRenderer extends ConvenienceRenderer { } protected forbiddenNamesForGlobalNamespace(): readonly string[] { - return [...globals, "Types", "JSON", "Dry", "Constructor", "Self"] as const; + return [ + ...globals, + "Types", + "JSON", + "Dry", + "Constructor", + "Self", + ] as const; } - protected forbiddenForObjectProperties(_c: ClassType, _classNamed: Name): ForbiddenWordsInfo { - return { names: forbiddenForObjectProperties, includeGlobalForbidden: true }; + protected forbiddenForObjectProperties( + _c: ClassType, + _classNamed: Name, + ): ForbiddenWordsInfo { + return { + names: forbiddenForObjectProperties, + includeGlobalForbidden: true, + }; } protected makeNamedTypeNamer(): Namer { - return new Namer("types", n => simpleNameStyle(n, true), []); + return new Namer("types", (n) => simpleNameStyle(n, true), []); } protected namerForObjectProperty(): Namer { @@ -62,35 +88,59 @@ export class RubyRenderer extends ConvenienceRenderer { } protected makeEnumCaseNamer(): Namer { - return new Namer("enum-cases", n => simpleNameStyle(n, true), []); + 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 => { + (_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]; - } + 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; } @@ -99,44 +149,67 @@ export class RubyRenderer extends ConvenienceRenderer { 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 => { + (_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 }; - } - }); + 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 this.exampleUse( + info.prop.type, + [exp, safeNav, ".", info.name], + depth, + info.prop.isOptional, + ); } return exp; }, - mapType => this.exampleUse(mapType.values, [exp, safeNav, '["…"]'], depth), - enumType => { + (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 => { + this.forEachEnumCase(enumType, "none", (theName) => { if (name === undefined) { name = theName; } }); if (name !== undefined) { - return [exp, " == ", this.nameForNamedType(enumType), "::", name]; + return [ + exp, + " == ", + this.nameForNamedType(enumType), + "::", + name, + ]; } return exp; }, - unionType => { + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { if (["class", "map", "array"].includes(nullable.kind)) { @@ -147,7 +220,7 @@ export class RubyRenderer extends ConvenienceRenderer { } return exp; - } + }, ); } @@ -155,57 +228,88 @@ export class RubyRenderer extends ConvenienceRenderer { function inner(): string { if (t instanceof ArrayType) { return "[…]"; - } else if (t instanceof MapType) { - return "{…}"; - } else if (t instanceof ClassType) { - return "{…}"; - } else { - return "…"; } + if (t instanceof MapType) { + return "{…}"; + } + if (t instanceof ClassType) { + return "{…}"; + } + + 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 ? "&" : ""; 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, ")"]; + (_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 => [ + (mapType) => [ ["Types::Hash", optional ? ".optional" : "", "[", e, "]"], safeAccess, ".map { |k, v| [k, ", this.fromDynamic(mapType.values, "v", false, true), "] }", safeAccess, - ".to_h" + ".to_h", ], - enumType => { - const expression = ["Types::", this.nameForNamedType(enumType), "[", e, "]"]; - return optional ? [e, ".nil? ? nil : ", expression] : expression; + (enumType) => { + const expression = [ + "Types::", + this.nameForNamedType(enumType), + "[", + e, + "]", + ]; + return optional + ? [e, ".nil? ? nil : ", expression] + : expression; }, - unionType => { + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { return this.fromDynamic(nullable, e, true); } - const expression = [this.nameForNamedType(unionType), ".from_dynamic!(", e, ")"]; + const expression = [ + this.nameForNamedType(unionType), + ".from_dynamic!(", + e, + ")", + ]; return optional ? [e, " ? ", expression, " : nil"] : expression; - } + }, ); } @@ -216,17 +320,29 @@ export class RubyRenderer extends ConvenienceRenderer { 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 => { + (_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); @@ -237,31 +353,31 @@ export class RubyRenderer extends ConvenienceRenderer { } 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 => { + (_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; - } + }, ); } @@ -271,25 +387,28 @@ export class RubyRenderer extends ConvenienceRenderer { 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, + (_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 => { + (_mapType) => false, + (_enumType) => true, + (unionType) => { const nullable = nullableFromUnion(unionType); if (nullable !== null) { - return this.propertyTypeMarshalsImplicitlyFromDynamic(nullable); + return this.propertyTypeMarshalsImplicitlyFromDynamic( + nullable, + ); } return false; - } + }, ); } @@ -311,7 +430,10 @@ export class RubyRenderer extends ConvenienceRenderer { } }; - if (this._options.namespace !== undefined && this._options.namespace !== "") { + if ( + this._options.namespace !== undefined && + this._options.namespace !== "" + ) { emitModuleInner(this._options.namespace); } else { emit(); @@ -325,10 +447,17 @@ export class RubyRenderer extends ConvenienceRenderer { let count = c.getProperties().size; this.forEachClassProperty(c, "none", (name, jsonName, p) => { const last = --count === 0; - const description = this.descriptionForClassProperty(c, jsonName); + 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) { @@ -360,26 +489,38 @@ export class RubyRenderer extends ConvenienceRenderer { 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)}")`; + 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, ","] - ]); - } - }); + 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(")"); @@ -395,10 +536,21 @@ export class RubyRenderer extends ConvenienceRenderer { 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.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("}"); @@ -425,9 +577,18 @@ export class RubyRenderer extends ConvenienceRenderer { 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.forEachUnionMember( + u, + u.getChildren(), + "none", + null, + (name, t) => { + table.push([ + ["attribute :", name, ", "], + [this.dryType(t, true)], + ]); + }, + ); this.emitTable(table); if (this._options.justTypes) { @@ -437,27 +598,60 @@ export class RubyRenderer extends ConvenienceRenderer { 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, ")"); + 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("rescue"); + this.emitLine("end"); + } + }, + ); this.emitLine('raise "Invalid union"'); }); @@ -469,13 +663,24 @@ export class RubyRenderer extends ConvenienceRenderer { 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; - }); + 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(() => { @@ -500,38 +705,83 @@ export class RubyRenderer extends ConvenienceRenderer { 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 => { + 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" + 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 (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.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.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`, + ], ]); } this.forEachEnum("none", (enumType, enumName) => { const cases: Sourcelike[][] = []; this.forEachEnumCase(enumType, "none", (_name, json) => { - cases.push([cases.length === 0 ? "" : ", ", `"${stringEscape(json)}"`]); + cases.push([ + cases.length === 0 ? "" : ", ", + `"${stringEscape(json)}"`, + ]); }); - declarations.push([[enumName], [" = ", this._options.strictness, "String.enum(", ...cases, ")"]]); + declarations.push([ + [enumName], + [ + " = ", + this._options.strictness, + "String.enum(", + ...cases, + ")", + ], + ]); }); if (declarations.length > 0) { @@ -545,18 +795,33 @@ export class RubyRenderer extends ConvenienceRenderer { 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 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( + "# 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( + "# ", + 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.emitLine( + "# If from_json! succeeds, the value returned matches the schema.", + ); } this.ensureBlankLine(); @@ -570,11 +835,15 @@ export class RubyRenderer extends ConvenienceRenderer { this.emitModule(() => { this.emitTypesModule(); - this.forEachDeclaration("leading-and-interposing", decl => { + 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.emitLine( + "class ", + this.nameForNamedType(decl.type), + " < Dry::Struct; end", + ); }); } }); @@ -583,7 +852,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) { @@ -598,23 +867,45 @@ export class RubyRenderer extends ConvenienceRenderer { 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.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)", + ), + ); + } + }, + ); }); }; @@ -622,7 +913,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/constants.ts b/packages/quicktype-core/src/language/Ruby/constants.ts index 9848048f..ae9f5bf7 100644 --- a/packages/quicktype-core/src/language/Ruby/constants.ts +++ b/packages/quicktype-core/src/language/Ruby/constants.ts @@ -39,7 +39,7 @@ export const keywords = [ "until", "when", "while", - "yield" + "yield", ] as const; const globalClasses = [ @@ -133,7 +133,7 @@ const globalClasses = [ "Undefined", "UnicodeNormalize", "Warning", - "ZeroDivisionError" + "ZeroDivisionError", ] as const; const kernel = [ @@ -286,7 +286,7 @@ const kernel = [ "untrace_var", "untrust", "untrusted?", - "warn" + "warn", ] as const; export const globals = [...kernel, ...globalClasses] as const; @@ -355,5 +355,5 @@ export const reservedProperties = [ "undef", "untrust", "while", - "with" + "with", ] as const; diff --git a/packages/quicktype-core/src/language/Ruby/language.ts b/packages/quicktype-core/src/language/Ruby/language.ts index e96c0109..e7b02130 100644 --- a/packages/quicktype-core/src/language/Ruby/language.ts +++ b/packages/quicktype-core/src/language/Ruby/language.ts @@ -1,7 +1,12 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { RubyRenderer } from "./RubyRenderer"; import { Strictness } from "./utils"; @@ -14,20 +19,28 @@ export const rubyOptions = { { strict: Strictness.Strict, coercible: Strictness.Coercible, - none: Strictness.None + none: Strictness.None, } as const, - "strict" + "strict", + ), + namespace: new StringOption( + "namespace", + "Specify a wrapping Namespace", + "NAME", + "", + "secondary", ), - namespace: new StringOption("namespace", "Specify a wrapping Namespace", "NAME", "", "secondary") }; export const rubyLanguageConfig = { displayName: "Ruby", names: ["ruby"], - extension: "rb" + extension: "rb", } as const; -export class RubyTargetLanguage extends TargetLanguage { +export class RubyTargetLanguage extends TargetLanguage< + typeof rubyLanguageConfig +> { public constructor() { super(rubyLanguageConfig); } @@ -44,7 +57,14 @@ export class RubyTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index 1b78d957..61c12f8c 100644 --- a/packages/quicktype-core/src/language/Ruby/utils.ts +++ b/packages/quicktype-core/src/language/Ruby/utils.ts @@ -11,7 +11,7 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap + utf32ConcatMap, } from "../../support/Strings"; import * as keywords from "./constants"; @@ -19,21 +19,28 @@ import * as keywords from "./constants"; export enum Strictness { Strict = "Strict::", Coercible = "Coercible::", - None = "Types::" + None = "Types::", } -export const forbiddenForObjectProperties = Array.from(new Set([...keywords.keywords, ...keywords.reservedProperties])); +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)); +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"].includes(category) || isStartCharacter(utf16Unit); + return ( + ["Nd", "Pc", "Mn", "Mc"].includes(category) || + isStartCharacter(utf16Unit) + ); } const legalizeName = legalizeCharacters(isPartCharacter); @@ -52,7 +59,7 @@ export function simpleNameStyle(original: string, uppercase: boolean): string { allUpperWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -66,6 +73,6 @@ export function memberNameStyle(original: string): string { allLowerWordStyle, allLowerWordStyle, "_", - isStartCharacter + isStartCharacter, ); } diff --git a/packages/quicktype-core/src/language/Rust/RustRenderer.ts b/packages/quicktype-core/src/language/Rust/RustRenderer.ts index 136f643f..22e81bab 100644 --- a/packages/quicktype-core/src/language/Rust/RustRenderer.ts +++ b/packages/quicktype-core/src/language/Rust/RustRenderer.ts @@ -1,19 +1,34 @@ /* 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 } from "../../Naming"; -import { type RenderContext } from "../../Renderer"; -import { type OptionValues } from "../../RendererOptions"; +import { + anyTypeIssueAnnotation, + nullTypeIssueAnnotation, +} from "../../Annotation"; +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, 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 "../../Type/TypeUtils"; +import type { TargetLanguage } from "../../TargetLanguage"; +import { + type ClassType, + type EnumType, + type Type, + UnionType, +} from "../../Type"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type rustOptions } from "./language"; +import type { rustOptions } from "./language"; import { Density, type NamingStyleKey, @@ -24,14 +39,14 @@ import { nameWithNamingStyle, namingStyles, rustStringEscape, - snakeNamingFunction + snakeNamingFunction, } from "./utils"; export class RustRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -56,15 +71,24 @@ export class RustRenderer extends ConvenienceRenderer { 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 }; } @@ -84,20 +108,39 @@ export class RustRenderer extends ConvenienceRenderer { private rustType(t: Type, withIssues = false): Sourcelike { return matchType( t, - _anyType => maybeAnnotated(withIssues, anyTypeIssueAnnotation, "Option"), - _nullType => maybeAnnotated(withIssues, nullTypeIssueAnnotation, "Option"), - _boolType => "bool", - _integerType => "i64", - _doubleType => "f64", - _stringType => "String", - arrayType => ["Vec<", this.rustType(arrayType.items, withIssues), ">"], - classType => this.nameForNamedType(classType), - mapType => ["HashMap"], - enumType => this.nameForNamedType(enumType), - unionType => { + (_anyType) => + maybeAnnotated( + withIssues, + anyTypeIssueAnnotation, + "Option", + ), + (_nullType) => + maybeAnnotated( + withIssues, + nullTypeIssueAnnotation, + "Option", + ), + (_boolType) => "bool", + (_integerType) => "i64", + (_doubleType) => "f64", + (_stringType) => "String", + (arrayType) => [ + "Vec<", + this.rustType(arrayType.items, withIssues), + ">", + ], + (classType) => this.nameForNamedType(classType), + (mapType) => [ + "HashMap", + ], + (enumType) => this.nameForNamedType(enumType), + (unionType) => { const nullable = nullableFromUnion(unionType); - if (nullable !== null) return this.nullableRustType(nullable, withIssues); + if (nullable !== null) + return this.nullableRustType(nullable, withIssues); const [hasNull] = removeNullFromUnion(unionType); @@ -107,8 +150,10 @@ export class RustRenderer extends ConvenienceRenderer { ? ["Box<", this.nameForNamedType(unionType), ">"] : this.nameForNamedType(unionType); - return hasNull !== null ? (["Option<", name, ">"] as Sourcelike) : name; - } + return hasNull !== null + ? (["Option<", name, ">"] as Sourcelike) + : name; + }, ); } @@ -123,10 +168,12 @@ export class RustRenderer extends ConvenienceRenderer { propName: Name, jsonName: string, defaultNamingStyle: NamingStyleKey, - preferedNamingStyle: NamingStyleKey + preferedNamingStyle: NamingStyleKey, ): void { const escapedName = rustStringEscape(jsonName); - const name = namingStyles[defaultNamingStyle].fromParts(this.sourcelikeToString(propName).split(" ")); + const name = namingStyles[defaultNamingStyle].fromParts( + this.sourcelikeToString(propName).split(" "), + ); const styledName = nameWithNamingStyle(name, preferedNamingStyle); const namesDiffer = escapedName !== styledName; if (namesDiffer) { @@ -137,14 +184,18 @@ export class RustRenderer extends ConvenienceRenderer { 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")]'); + if (nullable !== null) + this.emitLine( + '#[serde(skip_serializing_if = "Option::is_none")]', + ); } } private get visibility(): string { if (this._options.visibility === Visibility.Crate) { return "pub(crate) "; - } else if (this._options.visibility === Visibility.Public) { + } + if (this._options.visibility === Visibility.Public) { return "pub "; } @@ -158,32 +209,50 @@ export class RustRenderer extends ConvenienceRenderer { 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[] } = {}; this.forEachClassProperty(c, "none", (_name, jsonName, _prop) => { - propertiesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName); + propertiesNamingStyles[jsonName] = + listMatchingNamingStyles(jsonName); }); // Set the default naming style on the struct const defaultStyle = "snake_case"; - const preferedNamingStyle = getPreferredNamingStyle(Object.values(propertiesNamingStyles).flat(), defaultStyle); + const preferedNamingStyle = getPreferredNamingStyle( + Object.values(propertiesNamingStyles).flat(), + defaultStyle, + ); if (preferedNamingStyle !== defaultStyle) { this.emitLine(`#[serde(rename_all = "${preferedNamingStyle}")]`); } - const blankLines = this._options.density === Density.Dense ? "none" : "interposing"; + const blankLines = + this._options.density === Density.Dense ? "none" : "interposing"; const structBody = (): void => this.forEachClassProperty(c, blankLines, (name, jsonName, prop) => { - this.emitDescription(this.descriptionForClassProperty(c, jsonName)); - this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle); + this.emitDescription( + this.descriptionForClassProperty(c, jsonName), + ); + this.emitRenameAttribute( + name, + jsonName, + defaultStyle, + preferedNamingStyle, + ); if (this._options.skipSerializingNone) { this.emitSkipSerializeNone(prop.type); } - this.emitLine(this.visibility, name, ": ", this.breakCycle(prop.type, true), ","); + this.emitLine( + this.visibility, + name, + ": ", + this.breakCycle(prop.type, true), + ",", + ); }); this.emitBlock(["pub struct ", className], structBody); @@ -208,18 +277,25 @@ 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)]"); const [, nonNulls] = removeNullFromUnion(u); - const blankLines = this._options.density === Density.Dense ? "none" : "interposing"; + const blankLines = + this._options.density === Density.Dense ? "none" : "interposing"; this.emitBlock(["pub enum ", unionName], () => - this.forEachUnionMember(u, nonNulls, blankLines, null, (fieldName, t) => { - const rustType = this.breakCycle(t, true); - this.emitLine([fieldName, "(", rustType, "),"]); - }) + this.forEachUnionMember( + u, + nonNulls, + blankLines, + null, + (fieldName, t) => { + const rustType = this.breakCycle(t, true); + this.emitLine([fieldName, "(", rustType, "),"]); + }, + ), ); } @@ -230,28 +306,38 @@ export class RustRenderer extends ConvenienceRenderer { 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[] } = {}; this.forEachEnumCase(e, "none", (_name, jsonName) => { - enumCasesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName); + enumCasesNamingStyles[jsonName] = + listMatchingNamingStyles(jsonName); }); // Set the default naming style on the enum const defaultStyle = "PascalCase"; - const preferedNamingStyle = getPreferredNamingStyle(Object.values(enumCasesNamingStyles).flat(), defaultStyle); + const preferedNamingStyle = getPreferredNamingStyle( + Object.values(enumCasesNamingStyles).flat(), + defaultStyle, + ); if (preferedNamingStyle !== defaultStyle) { this.emitLine(`#[serde(rename_all = "${preferedNamingStyle}")]`); } - const blankLines = this._options.density === Density.Dense ? "none" : "interposing"; + const blankLines = + this._options.density === Density.Dense ? "none" : "interposing"; this.emitBlock(["pub enum ", enumName], () => this.forEachEnumCase(e, blankLines, (name, jsonName) => { - this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle); + this.emitRenameAttribute( + name, + jsonName, + defaultStyle, + preferedNamingStyle, + ); this.emitLine([name, ","]); - }) + }), ); } @@ -265,7 +351,9 @@ export class RustRenderer extends ConvenienceRenderer { return; } - const topLevelName = defined(mapFirst(this.topLevels)).getCombinedName(); + const topLevelName = defined( + mapFirst(this.topLevels), + ).getCombinedName(); this.emitMultiline( `// Example code that deserializes and serializes the model. // extern crate serde; @@ -278,7 +366,7 @@ export class RustRenderer extends ConvenienceRenderer { // fn main() { // let json = r#"{"answer": 42}"#; // let model: ${topLevelName} = serde_json::from_str(&json).unwrap(); -// }` +// }`, ); } @@ -301,14 +389,14 @@ 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), ); } } diff --git a/packages/quicktype-core/src/language/Rust/constants.ts b/packages/quicktype-core/src/language/Rust/constants.ts index 8ba3d3eb..7b56747f 100644 --- a/packages/quicktype-core/src/language/Rust/constants.ts +++ b/packages/quicktype-core/src/language/Rust/constants.ts @@ -72,5 +72,5 @@ export const keywords = [ "union", // Conflict between `std::Option` and potentially generated Option - "option" + "option", ] as const; diff --git a/packages/quicktype-core/src/language/Rust/language.ts b/packages/quicktype-core/src/language/Rust/language.ts index ac61b6fc..4981d6a6 100644 --- a/packages/quicktype-core/src/language/Rust/language.ts +++ b/packages/quicktype-core/src/language/Rust/language.ts @@ -1,7 +1,11 @@ -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, getOptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + getOptionValues, +} from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { RustRenderer } from "./RustRenderer"; import { Density, Visibility } from "./utils"; @@ -12,9 +16,9 @@ export const rustOptions = { "Density", { normal: Density.Normal, - dense: Density.Dense + dense: Density.Dense, } as const, - "normal" + "normal", ), visibility: new EnumOption( "visibility", @@ -22,25 +26,39 @@ export const rustOptions = { { private: Visibility.Private, crate: Visibility.Crate, - public: Visibility.Public + public: Visibility.Public, } as const, - "private" + "private", ), 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), + 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, + ), } as const; export const rustLanguageConfig = { displayName: "Rust", names: ["rust", "rs", "rustlang"], - extension: "rs" + extension: "rs", } as const; -export class RustTargetLanguage extends TargetLanguage { +export class RustTargetLanguage extends TargetLanguage< + typeof rustLanguageConfig +> { public constructor() { super(rustLanguageConfig); } @@ -49,7 +67,14 @@ export class RustTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): RustRenderer { + return new RustRenderer( + this, + renderContext, + getOptionValues(rustOptions, untypedOptionValues), + ); } } diff --git a/packages/quicktype-core/src/language/Rust/utils.ts b/packages/quicktype-core/src/language/Rust/utils.ts index 56e22af2..52e8b509 100644 --- a/packages/quicktype-core/src/language/Rust/utils.ts +++ b/packages/quicktype-core/src/language/Rust/utils.ts @@ -11,18 +11,18 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap + utf32ConcatMap, } from "../../support/Strings"; export enum Density { Normal = "Normal", - Dense = "Dense" + Dense = "Dense", } export enum Visibility { Private = "Private", Crate = "Crate", - Public = "Public" + Public = "Public", } type NameToParts = (name: string) => string[]; @@ -37,49 +37,70 @@ export const namingStyles = { 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]*)*$/, - toParts: (name: string): string[] => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")), + 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() + 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")), + 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(""), + }, } as const; namingStyles satisfies Record; @@ -117,14 +138,19 @@ function rustStyle(original: string, isSnakeCase: boolean): string { wordStyle, wordStyle, isSnakeCase ? "_" : "", - isAsciiLetterOrUnderscore + 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)); +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) { @@ -134,14 +160,21 @@ const standardUnicodeRustEscape = (codePoint: number): string => { } }; -export const rustStringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeRustEscape)); +export const rustStringEscape = utf32ConcatMap( + escapeNonPrintableMapper(isPrintable, standardUnicodeRustEscape), +); -export function getPreferredNamingStyle(namingStyleOccurences: string[], defaultStyle: NamingStyleKey): NamingStyleKey { - const occurrences = Object.fromEntries(Object.keys(namingStyles).map(key => [key, 0])); - namingStyleOccurences.forEach(style => ++occurrences[style]); +export function getPreferredNamingStyle( + namingStyleOccurences: string[], + defaultStyle: NamingStyleKey, +): NamingStyleKey { + 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).flatMap(([style, num]) => - num === max ? [style] : [] + const preferedStyles = Object.entries(occurrences).flatMap( + ([style, num]) => (num === max ? [style] : []), ) as NamingStyleKey[]; if (preferedStyles.includes(defaultStyle)) { return defaultStyle; @@ -151,12 +184,16 @@ export function getPreferredNamingStyle(namingStyleOccurences: string[], default } export function listMatchingNamingStyles(name: string): NamingStyleKey[] { - return Object.entries(namingStyles).flatMap(([namingStyleKey, { regex }]) => - regex.test(name) ? [namingStyleKey] : [] + return Object.entries(namingStyles).flatMap( + ([namingStyleKey, { regex }]) => + regex.test(name) ? [namingStyleKey] : [], ) as NamingStyleKey[]; } -export function nameWithNamingStyle(name: string, style: NamingStyleKey): string { +export function nameWithNamingStyle( + name: string, + style: NamingStyleKey, +): string { if (namingStyles[style].regex.test(name)) { return name; } diff --git a/packages/quicktype-core/src/language/Scala3/CirceRenderer.ts b/packages/quicktype-core/src/language/Scala3/CirceRenderer.ts index 36ee0cd6..348b585a 100644 --- a/packages/quicktype-core/src/language/Scala3/CirceRenderer.ts +++ b/packages/quicktype-core/src/language/Scala3/CirceRenderer.ts @@ -1,7 +1,18 @@ -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 "../../Type/TypeUtils"; +import type { Name } from "../../Naming"; +import type { Sourcelike } from "../../Source"; +import type { + ArrayType, + ClassType, + EnumType, + MapType, + Type, + UnionType, +} from "../../Type"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { Scala3Renderer } from "./Scala3Renderer"; import { wrapOption } from "./utils"; @@ -9,38 +20,77 @@ import { wrapOption } from "./utils"; 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 = "", + ): 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 => { + (_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(nullable), + "]", + ]; } + + return [ + "Encoder.AsObject[Option[", + this.nameForNamedType(nullable), + "]]", + ]; } - return ["Encoder.AsObject[", this.nameForNamedType(unionType), "]"]; - } + 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"); + this.emitLine( + "case class ", + className, + "() derives Encoder.AsObject, Decoder", + ); } protected anySourceType(optional: boolean): Sourcelike { @@ -85,13 +135,15 @@ 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( + "// If a union has a null in, then we'll need this too... ", + ); this.emitLine("type NullValue = None.type"); } @@ -105,7 +157,7 @@ export class CirceRenderer extends Scala3Renderer { elementType, "]] = Encoder.encodeMap[String, ", elementType, - "]" + "]", ]); } @@ -120,7 +172,7 @@ export class CirceRenderer extends Scala3Renderer { elementType, "]] = Encoder.encodeMap[String, ", elementType, - "]" + "]", ]); } @@ -146,24 +198,29 @@ export class CirceRenderer extends Scala3Renderer { theTypes.forEach((t, i) => { this.emitItem(i === 0 ? t : [" | ", t]); }); - const thisUnionType = theTypes.map(x => this.sourcelikeToString(x)).join(" | "); + const thisUnionType = theTypes + .map((x) => this.sourcelikeToString(x)) + .join(" | "); this.ensureBlankLine(); - if (!this.seenUnionTypes.some(y => y === thisUnionType)) { + 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]); + sourceLikeTypes.push([ + this.nameForUnionMember(u, maybeNull), + maybeNull, + ]); } this.emitLine(["given Decoder[", unionName, "] = {"]); this.indent(() => { this.emitLine(["List[Decoder[", unionName, "]]("]); this.indent(() => { - sourceLikeTypes.forEach(t => { + sourceLikeTypes.forEach((t) => { this.emitLine(["Decoder[", t[0], "].widen,"]); }); }); @@ -173,7 +230,11 @@ export class CirceRenderer extends Scala3Renderer { this.ensureBlankLine(); - this.emitLine(["given Encoder[", unionName, "] = Encoder.instance {"]); + this.emitLine([ + "given Encoder[", + unionName, + "] = Encoder.instance {", + ]); this.indent(() => { sourceLikeTypes.forEach((t, i) => { const paramTemp = `enc${i.toString()}`; @@ -183,7 +244,7 @@ export class CirceRenderer extends Scala3Renderer { " : ", t[0], " => ", - this.circeEncoderForType(t[1], false, false, paramTemp) + this.circeEncoderForType(t[1], false, false, paramTemp), ]); }); }); diff --git a/packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts b/packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts index 1d5bdec7..913fd614 100644 --- a/packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts +++ b/packages/quicktype-core/src/language/Scala3/Scala3Renderer.ts @@ -1,10 +1,16 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } 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 OptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated } from "../../Source"; -import { type TargetLanguage } from "../../TargetLanguage"; +import type { TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, @@ -13,19 +19,29 @@ import { MapType, type ObjectType, type Type, - type UnionType + type UnionType, } from "../../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../Type/TypeUtils"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type scala3Options } from "./language"; -import { lowerNamingFunction, scalaNameStyle, shouldAddBacktick, upperNamingFunction, wrapOption } from "./utils"; +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 + protected readonly _scalaOptions: OptionValues, ) { super(targetLanguage, renderContext); } @@ -34,15 +50,24 @@ export class Scala3Renderer extends ConvenienceRenderer { 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 }; } @@ -59,21 +84,28 @@ export class Scala3Renderer extends ConvenienceRenderer { } protected makeUnionMemberNamer(): Namer { - return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); + return funPrefixNamer( + "upper", + (s) => `${scalaNameStyle(true, s)}Value`, + ); } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate + return funPrefixNamer("upper", (s) => s.replace(" ", "")); // TODO - add backticks where appropriate } protected emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + this.emitCommentLines(lines, { + lineStart: " * ", + beforeComment: "/**", + afterComment: " */", + }); } protected emitBlock( line: Sourcelike, f: () => void, - delimiter: "curly" | "paren" | "lambda" | "none" = "curly" + delimiter: "curly" | "paren" | "lambda" | "none" = "curly", ): void { const [open, close] = delimiter === "curly" @@ -99,39 +131,59 @@ export class Scala3Renderer extends ConvenienceRenderer { } protected mapType(mapType: MapType, withIssues = false): Sourcelike { - return ["Map[String, ", this.scalaType(mapType.values, withIssues), "]"]; + 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)); + (_anyType) => { + return maybeAnnotated( + withIssues, + anyTypeIssueAnnotation, + this.anySourceType(!noOptional), + ); }, - _nullType => { + (_nullType) => { // return "None.type" - return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(!noOptional)); + 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 => { + (_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 [ + "Option[", + this.scalaType(nullable, withIssues), + "]", + ]; } return this.nameForNamedType(unionType); - } + }, ); } @@ -175,9 +227,9 @@ export class Scala3Renderer extends ConvenienceRenderer { const scalaType = (p: ClassProperty): Sourcelike => { if (p.isOptional) { return ["Option[", this.scalaType(p.type, true, true), "]"]; - } else { - return this.scalaType(p.type, true); } + + return this.scalaType(p.type, true); }; this.emitDescription(this.descriptionForType(c)); @@ -186,12 +238,18 @@ export class Scala3Renderer extends ConvenienceRenderer { 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 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); + const description = this.descriptionForClassProperty( + c, + jsonName, + ); if (description !== undefined) { meta.push(() => this.emitDescription(description)); } @@ -204,15 +262,22 @@ export class Scala3Renderer extends ConvenienceRenderer { emit(); } - const nameNeedsBackticks = jsonName.endsWith("_") || shouldAddBacktick(jsonName); - const nameWithBackticks = nameNeedsBackticks ? "`" + jsonName + "`" : jsonName; + const nameNeedsBackticks = + jsonName.endsWith("_") || shouldAddBacktick(jsonName); + const nameWithBackticks = nameNeedsBackticks + ? "`" + jsonName + "`" + : jsonName; this.emitLine( "val ", nameWithBackticks, " : ", scalaType(p), - p.isOptional ? " = None" : nullableOrOptional ? " = None" : "", - last ? "" : "," + p.isOptional + ? " = None" + : nullableOrOptional + ? " = None" + : "", + last ? "" : ",", ); if (meta.length > 0 && !last) { @@ -242,11 +307,11 @@ export class Scala3Renderer extends ConvenienceRenderer { } this.forEachEnumCase(e, "none", (name, jsonName) => { - if (!(jsonName == "")) { + if (!(jsonName === "")) { const backticks = shouldAddBacktick(jsonName) || jsonName.includes(" ") || - !isNaN(parseInt(jsonName.charAt(0))); + !Number.isNaN(Number.parseInt(jsonName.charAt(0))); if (backticks) { this.emitItem("`"); } @@ -262,7 +327,7 @@ export class Scala3Renderer extends ConvenienceRenderer { } }); }, - "none" + "none", ); } @@ -270,7 +335,7 @@ export class Scala3Renderer extends ConvenienceRenderer { function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; - return "_" + kind; + return `_${kind}`; } this.emitDescription(this.descriptionForType(u)); @@ -307,7 +372,7 @@ 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), ); } } diff --git a/packages/quicktype-core/src/language/Scala3/constants.ts b/packages/quicktype-core/src/language/Scala3/constants.ts index b41844e7..918172d7 100644 --- a/packages/quicktype-core/src/language/Scala3/constants.ts +++ b/packages/quicktype-core/src/language/Scala3/constants.ts @@ -24,7 +24,7 @@ export const invalidSymbols = [ ":", "~", "`", - "." + ".", ] as const; export const keywords = [ @@ -83,5 +83,5 @@ export const keywords = [ "Array", "List", "Map", - "Enum" + "Enum", ] as const; diff --git a/packages/quicktype-core/src/language/Scala3/language.ts b/packages/quicktype-core/src/language/Scala3/language.ts index 519034ca..235a202a 100644 --- a/packages/quicktype-core/src/language/Scala3/language.ts +++ b/packages/quicktype-core/src/language/Scala3/language.ts @@ -1,9 +1,13 @@ -import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; -import { type RenderContext } from "../../Renderer"; -import { EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import type { RenderContext } from "../../Renderer"; +import { + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { assertNever } from "../../support/Support"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { CirceRenderer } from "./CirceRenderer"; import { Scala3Renderer } from "./Scala3Renderer"; @@ -15,21 +19,23 @@ export const scala3Options = { "Serialization framework", { "just-types": "None", - "circe": "Circe", - "upickle": "Upickle" + circe: "Circe", + upickle: "Upickle", } as const, - "just-types" + "just-types", ), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), }; export const scala3LanguageConfig = { displayName: "Scala3", names: ["scala3"], - extension: "scala" + extension: "scala", } as const; -export class Scala3TargetLanguage extends TargetLanguage { +export class Scala3TargetLanguage extends TargetLanguage< + typeof scala3LanguageConfig +> { public constructor() { super(scala3LanguageConfig); } @@ -46,7 +52,10 @@ export class Scala3TargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): ConvenienceRenderer { const options = getOptionValues(scala3Options, untypedOptionValues); switch (options.framework) { diff --git a/packages/quicktype-core/src/language/Scala3/utils.ts b/packages/quicktype-core/src/language/Scala3/utils.ts index 1de23bcb..54b9ed00 100644 --- a/packages/quicktype-core/src/language/Scala3/utils.ts +++ b/packages/quicktype-core/src/language/Scala3/utils.ts @@ -8,7 +8,7 @@ import { isLetterOrUnderscore, isNumeric, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../../support/Strings"; import { invalidSymbols, keywords } from "./constants"; @@ -19,10 +19,10 @@ import { invalidSymbols, keywords } from "./constants"; */ 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))) + keywords.some((s) => paramName === s) || + invalidSymbols.some((s) => paramName.includes(s)) || + !isNaN(+Number.parseFloat(paramName)) || + !isNaN(Number.parseInt(paramName.charAt(0))) ); }; @@ -54,7 +54,7 @@ export function scalaNameStyle(isUpper: boolean, original: string): string { isUpper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } @@ -69,5 +69,9 @@ export function scalaNameStyle(isUpper: boolean, original: string): string { return _stringEscape(s).replace(/\$/g, "\\$"); } */ -export const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s)); -export const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); +export const upperNamingFunction = funPrefixNamer("upper", (s) => + scalaNameStyle(true, s), +); +export const lowerNamingFunction = funPrefixNamer("lower", (s) => + scalaNameStyle(false, s), +); diff --git a/packages/quicktype-core/src/language/Smithy4s/Smithy4sRenderer.ts b/packages/quicktype-core/src/language/Smithy4s/Smithy4sRenderer.ts index c7e293a7..da4141aa 100644 --- a/packages/quicktype-core/src/language/Smithy4s/Smithy4sRenderer.ts +++ b/packages/quicktype-core/src/language/Smithy4s/Smithy4sRenderer.ts @@ -1,10 +1,16 @@ -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } 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 OptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated } from "../../Source"; -import { type TargetLanguage } from "../../TargetLanguage"; +import type { TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, @@ -13,19 +19,29 @@ import { MapType, type ObjectType, type Type, - type UnionType + type UnionType, } from "../../Type"; -import { matchCompoundType, matchType, nullableFromUnion, removeNullFromUnion } from "../../Type/TypeUtils"; +import { + matchCompoundType, + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type smithyOptions } from "./language"; -import { lowerNamingFunction, scalaNameStyle, shouldAddBacktick, upperNamingFunction } from "./utils"; +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); } @@ -34,15 +50,24 @@ export class Smithy4sRenderer extends ConvenienceRenderer { 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 }; } @@ -59,21 +84,28 @@ export class Smithy4sRenderer extends ConvenienceRenderer { } protected makeUnionMemberNamer(): Namer { - return funPrefixNamer("upper", s => scalaNameStyle(true, s) + "Value"); + return funPrefixNamer( + "upper", + (s) => `${scalaNameStyle(true, s)}Value`, + ); } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("upper", s => s.replace(" ", "")); // TODO - add backticks where appropriate + return funPrefixNamer("upper", (s) => s.replace(" ", "")); // TODO - add backticks where appropriate } protected emitDescriptionBlock(lines: Sourcelike[]): void { - this.emitCommentLines(lines, { lineStart: " * ", beforeComment: "/**", afterComment: " */" }); + this.emitCommentLines(lines, { + lineStart: " * ", + beforeComment: "/**", + afterComment: " */", + }); } protected emitBlock( line: Sourcelike, f: () => void, - delimiter: "curly" | "paren" | "lambda" | "none" = "curly" + delimiter: "curly" | "paren" | "lambda" | "none" = "curly", ): void { const [open, close] = delimiter === "curly" @@ -108,32 +140,44 @@ export class Smithy4sRenderer extends ConvenienceRenderer { // 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)); + (_anyType) => { + return maybeAnnotated( + withIssues, + anyTypeIssueAnnotation, + this.anySourceType(!noOptional), + ); }, - _nullType => { + (_nullType) => { // return "None.type" - return maybeAnnotated(withIssues, nullTypeIssueAnnotation, this.anySourceType(!noOptional)); + 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 => { + (_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.scalaType(nullable, withIssues)]; } return this.nameForNamedType(unionType); - } + }, ); } @@ -164,7 +208,13 @@ export class Smithy4sRenderer extends ConvenienceRenderer { protected emitTopLevelMap(t: MapType, name: Name): void { const elementType = this.scalaType(t.values); - this.emitLine(["map ", name, " { map[ key : String , value : ", elementType, "}"]); + this.emitLine([ + "map ", + name, + " { map[ key : String , value : ", + elementType, + "}", + ]); } protected emitEmptyClassDefinition(c: ClassType, className: Name): void { @@ -181,9 +231,9 @@ export class Smithy4sRenderer extends ConvenienceRenderer { const scalaType = (p: ClassProperty): Sourcelike => { if (p.isOptional) { return [this.scalaType(p.type, true, true)]; - } else { - return [this.scalaType(p.type, true)]; } + + return [this.scalaType(p.type, true)]; }; const emitLater: ClassProperty[] = []; @@ -195,17 +245,24 @@ export class Smithy4sRenderer extends ConvenienceRenderer { 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 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 laterType = p.type.kind === "array" || p.type.kind === "map"; + const laterType = + p.type.kind === "array" || p.type.kind === "map"; if (laterType) { emitLater.push(p); } - const description = this.descriptionForClassProperty(c, jsonName); + const description = this.descriptionForClassProperty( + c, + jsonName, + ); if (description !== undefined) { meta.push(() => this.emitDescription(description)); } @@ -218,15 +275,18 @@ export class Smithy4sRenderer extends ConvenienceRenderer { emit(); } - const nameNeedsBackticks = jsonName.endsWith("_") || shouldAddBacktick(jsonName); - const nameWithBackticks = nameNeedsBackticks ? "`" + jsonName + "`" : jsonName; + const nameNeedsBackticks = + jsonName.endsWith("_") || shouldAddBacktick(jsonName); + const nameWithBackticks = nameNeedsBackticks + ? "`" + jsonName + "`" + : jsonName; this.emitLine( p.isOptional ? "" : nullableOrOptional ? "" : "@required ", nameWithBackticks, " : ", scalaType(p), - last ? "" : "," + last ? "" : ",", ); if (meta.length > 0 && !last) { @@ -241,34 +301,34 @@ export class Smithy4sRenderer extends ConvenienceRenderer { protected emitClassDefinitionMethods(arrayTypes: ClassProperty[]): void { this.emitLine("}"); - arrayTypes.forEach(p => { + arrayTypes.forEach((p) => { function ignore(_: T): void { return; } matchCompoundType( p.type, - at => { + (at) => { this.emitLine([ "list ", this.scalaType(at, true), "{ member: ", this.scalaType(at.items, true), - "}" + "}", ]); }, ignore, - mt => { + (mt) => { this.emitLine([ "map ", this.scalaType(mt, true), "{ key: String , value: ", this.scalaType(mt.values, true), - "}" + "}", ]); }, ignore, - ignore + ignore, ); }); } @@ -306,7 +366,7 @@ export class Smithy4sRenderer extends ConvenienceRenderer { function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; - return "_" + kind; + return `_${kind}`; } const emitLater: Type[] = []; @@ -336,34 +396,34 @@ export class Smithy4sRenderer extends ConvenienceRenderer { this.emitLine("}"); this.ensureBlankLine(); - emitLater.forEach(p => { + emitLater.forEach((p) => { function ignore(_: T): void { return; } matchCompoundType( p, - at => { + (at) => { this.emitLine([ "list ", this.scalaType(at, true), "{ member: ", this.scalaType(at.items, true), - "}" + "}", ]); }, ignore, - mt => { + (mt) => { this.emitLine([ "map ", this.scalaType(mt, true), "{ key: String , value: ", this.scalaType(mt.values, true), - "}" + "}", ]); }, ignore, - ignore + ignore, ); }); } @@ -384,7 +444,7 @@ 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), ); } } diff --git a/packages/quicktype-core/src/language/Smithy4s/constants.ts b/packages/quicktype-core/src/language/Smithy4s/constants.ts index e015b6ea..66660e7b 100644 --- a/packages/quicktype-core/src/language/Smithy4s/constants.ts +++ b/packages/quicktype-core/src/language/Smithy4s/constants.ts @@ -23,7 +23,7 @@ export const invalidSymbols = [ ":", "~", "`", - "." + ".", ] as const; export const keywords = [ @@ -73,5 +73,5 @@ export const keywords = [ "Array", "List", "Map", - "Enum" + "Enum", ] as const; diff --git a/packages/quicktype-core/src/language/Smithy4s/language.ts b/packages/quicktype-core/src/language/Smithy4s/language.ts index 25b0b1c0..38186c8b 100644 --- a/packages/quicktype-core/src/language/Smithy4s/language.ts +++ b/packages/quicktype-core/src/language/Smithy4s/language.ts @@ -1,14 +1,18 @@ -import { type ConvenienceRenderer } from "../../ConvenienceRenderer"; -import { type RenderContext } from "../../Renderer"; -import { EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { ConvenienceRenderer } from "../../ConvenienceRenderer"; +import type { RenderContext } from "../../Renderer"; +import { + EnumOption, + StringOption, + getOptionValues, +} from "../../RendererOptions"; import { assertNever } from "../../support/Support"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { Smithy4sRenderer } from "./Smithy4sRenderer"; export enum Framework { - None = "None" + None = "None", } export const smithyOptions = { @@ -17,18 +21,20 @@ export const smithyOptions = { "framework", "Serialization framework", { "just-types": Framework.None } as const, - "just-types" + "just-types", ), - packageName: new StringOption("package", "Package", "PACKAGE", "quicktype") + packageName: new StringOption("package", "Package", "PACKAGE", "quicktype"), }; export const smithyLanguageConfig = { displayName: "Smithy", names: ["smithy4a"], - extension: "smithy" + extension: "smithy", } as const; -export class SmithyTargetLanguage extends TargetLanguage { +export class SmithyTargetLanguage extends TargetLanguage< + typeof smithyLanguageConfig +> { public constructor() { super(smithyLanguageConfig); } @@ -45,7 +51,10 @@ export class SmithyTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): ConvenienceRenderer { const options = getOptionValues(smithyOptions, untypedOptionValues); switch (options.framework) { diff --git a/packages/quicktype-core/src/language/Smithy4s/utils.ts b/packages/quicktype-core/src/language/Smithy4s/utils.ts index 7075f662..a3d44bb4 100644 --- a/packages/quicktype-core/src/language/Smithy4s/utils.ts +++ b/packages/quicktype-core/src/language/Smithy4s/utils.ts @@ -9,7 +9,7 @@ import { isLetterOrUnderscore, isNumeric, legalizeCharacters, - splitIntoWords + splitIntoWords, } from "../../support/Strings"; import { invalidSymbols, keywords } from "./constants"; @@ -20,10 +20,10 @@ import { invalidSymbols, keywords } from "./constants"; */ 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))) + keywords.some((s) => paramName === s) || + invalidSymbols.some((s) => paramName.includes(s)) || + !isNaN(Number.parseFloat(paramName)) || + !isNaN(Number.parseInt(paramName.charAt(0))) ); }; @@ -47,9 +47,13 @@ export function scalaNameStyle(isUpper: boolean, original: string): string { isUpper ? allUpperWordStyle : allLowerWordStyle, allUpperWordStyle, "", - isStartCharacter + isStartCharacter, ); } -export const upperNamingFunction = funPrefixNamer("upper", s => scalaNameStyle(true, s)); -export const lowerNamingFunction = funPrefixNamer("lower", s => scalaNameStyle(false, s)); +export const upperNamingFunction = funPrefixNamer("upper", (s) => + scalaNameStyle(true, s), +); +export const lowerNamingFunction = funPrefixNamer("lower", (s) => + scalaNameStyle(false, s), +); diff --git a/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts b/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts index aeba703a..638c15fc 100644 --- a/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts +++ b/packages/quicktype-core/src/language/Swift/SwiftRenderer.ts @@ -1,15 +1,21 @@ import { arrayIntercalate } from "collection-utils"; -import { anyTypeIssueAnnotation, nullTypeIssueAnnotation } from "../../Annotation"; -import { ConvenienceRenderer, type ForbiddenWordsInfo } 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 OptionValues } from "../../RendererOptions"; +import type { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; import { type Sourcelike, maybeAnnotated, modifySource } from "../../Source"; import { acronymStyle } from "../../support/Acronyms"; import { camelCase } from "../../support/Strings"; import { assert, defined, panic } from "../../support/Support"; -import { type TargetLanguage } from "../../TargetLanguage"; +import type { TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, @@ -18,13 +24,22 @@ import { MapType, type Type, type TypeKind, - type UnionType + type UnionType, } from "../../Type"; -import { matchType, nullableFromUnion, removeNullFromUnion } from "../../Type/TypeUtils"; +import { + matchType, + nullableFromUnion, + removeNullFromUnion, +} from "../../Type/TypeUtils"; import { keywords } from "./constants"; -import { type swiftOptions } from "./language"; -import { MAX_SAMELINE_PROPERTIES, type SwiftProperty, stringEscape, swiftNameStyle } from "./utils"; +import type { swiftOptions } from "./language"; +import { + MAX_SAMELINE_PROPERTIES, + type SwiftProperty, + stringEscape, + swiftNameStyle, +} from "./utils"; export class SwiftRenderer extends ConvenienceRenderer { private _currentFilename: string | undefined; @@ -36,7 +51,7 @@ export class SwiftRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -49,21 +64,35 @@ 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 { - return funPrefixNamer("upper", s => - swiftNameStyle(this._options.namedTypePrefix, true, s, acronymStyle(this._options.acronymStyle)) + return funPrefixNamer("upper", (s) => + swiftNameStyle( + this._options.namedTypePrefix, + true, + s, + acronymStyle(this._options.acronymStyle), + ), ); } @@ -98,67 +127,100 @@ export class SwiftRenderer extends ConvenienceRenderer { this.emitBlock([this.accessLevel, line], f); } - private justTypesCase(justTypes: Sourcelike, notJustTypes: Sourcelike): Sourcelike { - if (this._options.justTypes) return justTypes; - else return notJustTypes; + private justTypesCase( + justTypes: Sourcelike, + notJustTypes: Sourcelike, + ): Sourcelike { + if (this._options.justTypes) { + return justTypes; + } + + return notJustTypes; } private get lowerNamingFunction(): Namer { - return funPrefixNamer("lower", s => swiftNameStyle("", false, s, acronymStyle(this._options.acronymStyle))); + 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")) { + if ( + p.isOptional || + (this._options.optionalEnums && p.type.kind === "enum") + ) { return [this.swiftType(p.type, true, true), "?"]; - } else { - return this.swiftType(p.type, true); } + + 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, - _anyType => { + (_anyType) => { this._needAny = true; return maybeAnnotated( withIssues, anyTypeIssueAnnotation, - this.justTypesCase(["Any", optional], "JSONAny") + this.justTypesCase(["Any", optional], "JSONAny"), ); }, - _nullType => { + (_nullType) => { this._needNull = true; return maybeAnnotated( withIssues, nullTypeIssueAnnotation, - this.justTypesCase("NSNull", ["JSONNull", optional]) + this.justTypesCase("NSNull", ["JSONNull", optional]), ); }, - _boolType => "Bool", - _integerType => "Int", - _doubleType => "Double", - _stringType => "String", - arrayType => ["[", this.swiftType(arrayType.items, withIssues), "]"], - classType => this.nameForNamedType(classType), - mapType => ["[String: ", this.swiftType(mapType.values, withIssues), "]"], - enumType => this.nameForNamedType(enumType), - unionType => { + (_boolType) => "Bool", + (_integerType) => "Int", + (_doubleType) => "Double", + (_stringType) => "String", + (arrayType) => [ + "[", + this.swiftType(arrayType.items, withIssues), + "]", + ], + (classType) => this.nameForNamedType(classType), + (mapType) => [ + "[String: ", + this.swiftType(mapType.values, withIssues), + "]", + ], + (enumType) => this.nameForNamedType(enumType), + (unionType) => { const nullable = nullableFromUnion(unionType); - if (nullable !== null) return [this.swiftType(nullable, withIssues), optional]; + if (nullable !== null) + return [this.swiftType(nullable, withIssues), optional]; return this.nameForNamedType(unionType); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return "Date"; - } else { - return panic(`Transformed string type ${transformedStringType.kind} not supported`); } - } + + 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"; } @@ -171,17 +233,24 @@ export class SwiftRenderer extends ConvenienceRenderer { } 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( + "// 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("//"); this.forEachTopLevel("none", (t, topLevelName) => { - if (this._options.convenienceInitializers && !(t instanceof EnumType)) { + if ( + this._options.convenienceInitializers && + !(t instanceof EnumType) + ) { this.emitLineOnce( "// let ", modifySource(camelCase, topLevelName), " = try ", topLevelName, - "(json)" + "(json)", ); } else { this.emitLineOnce( @@ -190,7 +259,7 @@ export class SwiftRenderer extends ConvenienceRenderer { " = ", "try? JSONDecoder().decode(", topLevelName, - ".self, from: jsonData)" + ".self, from: jsonData)", ); } }); @@ -202,12 +271,23 @@ export class SwiftRenderer extends ConvenienceRenderer { } 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("// To parse the JSON, add this file to your project and do:"); this.emitLineOnce("//"); - if (this._options.convenienceInitializers && !(type instanceof EnumType)) { - this.emitLine("// let ", modifySource(camelCase, name), " = try ", name, "(json)"); + if ( + this._options.convenienceInitializers && + !(type instanceof EnumType) + ) { + this.emitLine( + "// let ", + modifySource(camelCase, name), + " = try ", + name, + "(json)", + ); } else { this.emitLine( "// let ", @@ -215,7 +295,7 @@ export class SwiftRenderer extends ConvenienceRenderer { " = ", "try? newJSONDecoder().decode(", name, - ".self, from: jsonData)" + ".self, from: jsonData)", ); } } @@ -224,23 +304,36 @@ export class SwiftRenderer extends ConvenienceRenderer { this.emitLine("//"); this.emitLine("// To parse values from Alamofire responses:"); this.emitLine("//"); - this.emitLine("// Alamofire.request(url).response", name, " { response in"); - this.emitLine("// if let ", modifySource(camelCase, name), " = response.result.value {"); + this.emitLine( + "// Alamofire.request(url).response", + name, + " { response in", + ); + this.emitLine( + "// if let ", + modifySource(camelCase, name), + " = response.result.value {", + ); this.emitLine("// ..."); this.emitLine("// }"); this.emitLine("// }"); } - if (this._options.protocol.hashable || this._options.protocol.equatable) { + if ( + this._options.protocol.hashable || + this._options.protocol.equatable + ) { 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.emitLine("// synthesized for types that have collections (such as arrays or dictionaries)."); } } @@ -251,14 +344,22 @@ export class SwiftRenderer extends ConvenienceRenderer { } if (this._options.optionalEnums) { - this.emitLineOnce("import OptionallyDecodable // https://github.com/idrougge/OptionallyDecodable"); + this.emitLineOnce( + "import OptionallyDecodable // https://github.com/idrougge/OptionallyDecodable", + ); } this.ensureBlankLine(); } private renderTopLevelAlias(t: Type, name: Name): void { - this.emitLine(this.accessLevel, "typealias ", name, " = ", this.swiftType(t, true)); + this.emitLine( + this.accessLevel, + "typealias ", + name, + " = ", + this.swiftType(t, true), + ); } protected getProtocolsArray(kind: "struct" | "class" | "enum"): string[] { @@ -283,7 +384,11 @@ export class SwiftRenderer extends ConvenienceRenderer { protocols.push("Equatable"); } - if (this._options.sendable && (!this._options.mutableProperties || !isClass) && !this._options.objcSupport) { + if ( + this._options.sendable && + (!this._options.mutableProperties || !isClass) && + !this._options.objcSupport + ) { protocols.push("Sendable"); } @@ -292,20 +397,20 @@ export class SwiftRenderer extends ConvenienceRenderer { private getProtocolString( kind: "struct" | "class" | "enum", - baseClass: string | undefined = undefined + baseClass: string | undefined = undefined, ): Sourcelike { - let protocols = this.getProtocolsArray(kind); + const protocols = this.getProtocolsArray(kind); if (baseClass) { protocols.unshift(baseClass); } - return protocols.length > 0 ? ": " + protocols.join(", ") : ""; + return protocols.length > 0 ? `: ${protocols.join(", ")}` : ""; } private getEnumPropertyGroups(c: ClassType): typeof groups { type PropertyGroup = Array<{ label?: string; name: Name }>; - let groups: PropertyGroup[] = []; + const groups: PropertyGroup[] = []; let group: PropertyGroup = []; this.forEachClassProperty(c, "none", (name, jsonName) => { @@ -352,7 +457,10 @@ export class SwiftRenderer extends ConvenienceRenderer { return; } - assert(this._currentFilename === undefined, "Previous file wasn't finished: " + this._currentFilename); + assert( + this._currentFilename === undefined, + `Previous file wasn't finished: ${this._currentFilename}`, + ); // FIXME: The filenames should actually be Sourcelikes, too this._currentFilename = `${this.sourcelikeToString(basename)}.swift`; this.initializeEmitContextForFilename(this._currentFilename); @@ -368,14 +476,17 @@ 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), ]; } @@ -395,136 +506,192 @@ export class SwiftRenderer extends ConvenienceRenderer { this.emitItem(this.objcMembersDeclaration); } - this.emitBlockWithAccess([structOrClass, " ", className, this.getProtocolString(structOrClass)], () => { - if (this._options.dense) { - let lastProperty: ClassProperty | undefined = undefined; - let lastNames: Name[] = []; + this.emitBlockWithAccess( + [ + structOrClass, + " ", + className, + this.getProtocolString(structOrClass), + ], + () => { + if (this._options.dense) { + let lastProperty: ClassProperty | undefined = undefined; + let lastNames: Name[] = []; - const emitLastProperty = (): void => { - if (lastProperty === undefined) return; + const emitLastProperty = (): void => { + if (lastProperty === undefined) return; - const useMutableProperties = this._options.mutableProperties; + const useMutableProperties = + this._options.mutableProperties; - let sources: Sourcelike[] = [ - [ - this._options.optionalEnums && lastProperty.type.kind === "enum" - ? "@OptionallyDecodable " - : "", - this.accessLevel, - useMutableProperties || (this._options.optionalEnums && lastProperty.type.kind === "enum") - ? "var " - : "let " - ] - ]; - lastNames.forEach((n, i) => { - if (i > 0) sources.push(", "); - sources.push(n); - }); - sources.push(": "); - sources.push(this.swiftPropertyType(lastProperty)); - this.emitLine(sources); + const sources: Sourcelike[] = [ + [ + this._options.optionalEnums && + lastProperty.type.kind === "enum" + ? "@OptionallyDecodable " + : "", + this.accessLevel, + useMutableProperties || + (this._options.optionalEnums && + lastProperty.type.kind === "enum") + ? "var " + : "let ", + ], + ]; + lastNames.forEach((n, i) => { + if (i > 0) sources.push(", "); + sources.push(n); + }); + sources.push(": "); + sources.push(this.swiftPropertyType(lastProperty)); + this.emitLine(sources); - lastProperty = undefined; - lastNames = []; - }; + lastProperty = undefined; + lastNames = []; + }; - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - const description = this.descriptionForClassProperty(c, jsonName); - if ( - (lastProperty && !p.equals(lastProperty)) || - lastNames.length >= MAX_SAMELINE_PROPERTIES || - description !== undefined - ) { - emitLastProperty(); - } - - if (lastProperty === undefined) { - lastProperty = p; - } - - lastNames.push(name); - if (description !== undefined) { - this.emitDescription(description); - emitLastProperty(); - } - }); - emitLastProperty(); - } else { - this.forEachClassProperty(c, "none", (name, jsonName, p) => { - const description = this.descriptionForClassProperty(c, jsonName); - const propertyLines = this.propertyLinesDefinition(name, p); - this.emitDescription(description); - this.emitLine(propertyLines); - }); - } - - if (!this._options.justTypes) { - const groups = this.getEnumPropertyGroups(c); - const allPropertiesRedundant = groups.every(group => { - return group.every(p => p.label === undefined); - }); - if (!allPropertiesRedundant && c.getProperties().size > 0) { - this.ensureBlankLine(); - let enumDeclaration = this.accessLevel; - enumDeclaration += "enum CodingKeys: String, CodingKey"; - if (this._options.codingKeysProtocol && this._options.codingKeysProtocol.length > 0) { - enumDeclaration += ", "; - enumDeclaration += this._options.codingKeysProtocol; - } - - this.emitBlock(enumDeclaration, () => { - for (const group of groups) { - const { name, label } = group[0]; - if (this._options.explicitCodingKeys && label !== undefined) { - this.emitLine("case ", name, ' = "', label, '"'); - } else { - const names = arrayIntercalate( - ", ", - group.map(p => p.name) - ); - this.emitLine("case ", names); + this.forEachClassProperty( + c, + "none", + (name, jsonName, p) => { + const description = + this.descriptionForClassProperty(c, jsonName); + if ( + (lastProperty && !p.equals(lastProperty)) || + lastNames.length >= MAX_SAMELINE_PROPERTIES || + description !== undefined + ) { + emitLastProperty(); } - } - }); - } - } - // this main initializer must be defined within the class - // declaration since it assigns let constants - if ( - isClass || - // Public structs need explicit initializers - // https://github.com/quicktype/quicktype/issues/899 - this._options.accessLevel === "public" - ) { - // Make an initializer that initalizes all fields - this.ensureBlankLine(); - let initProperties = this.initializableProperties(c); - let propertiesLines: Sourcelike[] = []; - for (let property of initProperties) { - if (propertiesLines.length > 0) propertiesLines.push(", "); - propertiesLines.push(property.name, ": ", this.swiftPropertyType(property.parameter)); - } + if (lastProperty === undefined) { + lastProperty = p; + } - if (this.propertyCount(c) === 0 && this._options.objcSupport) { - this.emitBlockWithAccess(["override init()"], () => { - return ""; - }); + lastNames.push(name); + if (description !== undefined) { + this.emitDescription(description); + emitLastProperty(); + } + }, + ); + emitLastProperty(); } else { - this.emitBlockWithAccess(["init(", ...propertiesLines, ")"], () => { - for (let property of initProperties) { - this.emitLine("self.", property.name, " = ", property.name); - } - }); + this.forEachClassProperty( + c, + "none", + (name, jsonName, p) => { + const description = + this.descriptionForClassProperty(c, jsonName); + const propertyLines = this.propertyLinesDefinition( + name, + p, + ); + this.emitDescription(description); + this.emitLine(propertyLines); + }, + ); } - } - }); + + if (!this._options.justTypes) { + const groups = this.getEnumPropertyGroups(c); + const allPropertiesRedundant = groups.every((group) => { + return group.every((p) => p.label === undefined); + }); + if (!allPropertiesRedundant && c.getProperties().size > 0) { + this.ensureBlankLine(); + let enumDeclaration = this.accessLevel; + enumDeclaration += "enum CodingKeys: String, CodingKey"; + if ( + this._options.codingKeysProtocol && + this._options.codingKeysProtocol.length > 0 + ) { + enumDeclaration += ", "; + enumDeclaration += this._options.codingKeysProtocol; + } + + this.emitBlock(enumDeclaration, () => { + for (const group of groups) { + const { name, label } = group[0]; + if ( + this._options.explicitCodingKeys && + label !== undefined + ) { + this.emitLine( + "case ", + name, + ' = "', + label, + '"', + ); + } else { + const names = arrayIntercalate( + ", ", + group.map((p) => p.name), + ); + this.emitLine("case ", names); + } + } + }); + } + } + + // this main initializer must be defined within the class + // declaration since it assigns let constants + if ( + isClass || + // Public structs need explicit initializers + // https://github.com/quicktype/quicktype/issues/899 + this._options.accessLevel === "public" + ) { + // Make an initializer that initalizes all fields + this.ensureBlankLine(); + const initProperties = this.initializableProperties(c); + const propertiesLines: Sourcelike[] = []; + for (const property of initProperties) { + 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 ""; + }); + } else { + this.emitBlockWithAccess( + ["init(", ...propertiesLines, ")"], + () => { + for (const property of initProperties) { + this.emitLine( + "self.", + property.name, + " = ", + property.name, + ); + } + }, + ); + } + } + }, + ); if (!this._options.justTypes) { // FIXME: We emit only the MARK line for top-level-enum.schema if (this._options.convenienceInitializers) { this.ensureBlankLine(); - this.emitMark(this.sourcelikeToString(className) + " convenience initializers and mutators"); + this.emitMark( + this.sourcelikeToString(className) + + " convenience initializers and mutators", + ); this.ensureBlankLine(); this.emitConvenienceInitializersExtension(c, className); this.ensureBlankLine(); @@ -536,10 +703,14 @@ export class SwiftRenderer extends ConvenienceRenderer { protected initializableProperties(c: ClassType): SwiftProperty[] { const properties: SwiftProperty[] = []; - this.forEachClassProperty(c, "none", (name, jsonName, parameter, position) => { - const property = { name, jsonName, parameter, position }; - properties.push(property); - }); + this.forEachClassProperty( + c, + "none", + (name, jsonName, parameter, position) => { + const property = { name, jsonName, parameter, position }; + properties.push(property); + }, + ); return properties; } @@ -547,9 +718,14 @@ export class SwiftRenderer extends ConvenienceRenderer { this.emitBlock("func newJSONDecoder() -> JSONDecoder", () => { this.emitLine("let decoder = JSONDecoder()"); if (!this._options.linux) { - this.emitBlock("if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)", () => { - this.emitLine("decoder.dateDecodingStrategy = .iso8601"); - }); + this.emitBlock( + "if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)", + () => { + this.emitLine( + "decoder.dateDecodingStrategy = .iso8601", + ); + }, + ); } else { this.emitMultiline(`decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in let container = try decoder.singleValueContainer() @@ -577,9 +753,14 @@ export class SwiftRenderer extends ConvenienceRenderer { this.emitBlock("func newJSONEncoder() -> JSONEncoder", () => { this.emitLine("let encoder = JSONEncoder()"); if (!this._options.linux) { - this.emitBlock("if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)", () => { - this.emitLine("encoder.dateEncodingStrategy = .iso8601"); - }); + this.emitBlock( + "if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)", + () => { + this.emitLine( + "encoder.dateEncodingStrategy = .iso8601", + ); + }, + ); } else { this.emitMultiline(`let formatter = DateFormatter() formatter.calendar = Calendar(identifier: .iso8601) @@ -593,7 +774,10 @@ 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 " : ""; @@ -601,13 +785,21 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); if (isClass) { this.emitBlock("convenience init(data: Data) throws", () => { if (this.propertyCount(c) > 0) { - this.emitLine("let me = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)"); + this.emitLine( + "let me = try newJSONDecoder().decode(", + this.swiftType(c), + ".self, from: data)", + ); } else { - this.emitLine("let _ = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)"); + this.emitLine( + "let _ = try newJSONDecoder().decode(", + this.swiftType(c), + ".self, from: data)", + ); } - let args: Sourcelike[] = []; - this.forEachClassProperty(c, "none", name => { + const args: Sourcelike[] = []; + this.forEachClassProperty(c, "none", (name) => { if (args.length > 0) args.push(", "); args.push(name, ": ", "me.", name); }); @@ -615,24 +807,41 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); }); } else { this.emitBlock("init(data: Data) throws", () => { - this.emitLine("self = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)"); + 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"], + [ + 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.emitBlock( + "guard let data = json.data(using: encoding) else", + () => { + 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.emitLine("try self.init(data: try Data(contentsOf: url))"); - }); + this.emitBlock( + [convenience, "init(fromURL url: URL) throws"], + () => { + this.emitLine( + "try self.init(data: try Data(contentsOf: url))", + ); + }, + ); this.ensureBlankLine(); this.emitConvenienceMutator(c, className); @@ -643,9 +852,14 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.emitLine("return try newJSONEncoder().encode(self)"); }); this.ensureBlankLine(); - this.emitBlock("func jsonString(encoding: String.Encoding = .utf8) throws -> String?", () => { - this.emitLine("return String(data: try self.jsonData(), encoding: encoding)"); - }); + this.emitBlock( + "func jsonString(encoding: String.Encoding = .utf8) throws -> String?", + () => { + this.emitLine( + "return String(data: try self.jsonData(), encoding: encoding)", + ); + }, + ); }); } @@ -659,17 +873,29 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); const protocolString = this.getProtocolString("enum", "String"); if (this._options.justTypes) { - this.emitBlockWithAccess(["enum ", enumName, protocolString], () => { - this.forEachEnumCase(e, "none", name => { - this.emitLine("case ", name); - }); - }); + this.emitBlockWithAccess( + ["enum ", enumName, protocolString], + () => { + this.forEachEnumCase(e, "none", (name) => { + this.emitLine("case ", name); + }); + }, + ); } else { - this.emitBlockWithAccess(["enum ", enumName, protocolString], () => { - this.forEachEnumCase(e, "none", (name, jsonName) => { - this.emitLine("case ", name, ' = "', stringEscape(jsonName), '"'); - }); - }); + this.emitBlockWithAccess( + ["enum ", enumName, protocolString], + () => { + this.forEachEnumCase(e, "none", (name, jsonName) => { + this.emitLine( + "case ", + name, + ' = "', + stringEscape(jsonName), + '"', + ); + }); + }, + ); } this.endFile(); @@ -684,92 +910,177 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); function sortBy(t: Type): string { const kind = t.kind; if (kind === "class") return kind; - return "_" + kind; + return `_${kind}`; } const renderUnionCase = (t: Type): void => { - this.emitBlock(["if let x = try? container.decode(", this.swiftType(t), ".self)"], () => { - this.emitLine("self = .", this.nameForUnionMember(u, t), "(x)"); - this.emitLine("return"); - }); + this.emitBlock( + [ + "if let x = try? container.decode(", + this.swiftType(t), + ".self)", + ], + () => { + this.emitLine( + "self = .", + this.nameForUnionMember(u, t), + "(x)", + ); + this.emitLine("return"); + }, + ); }; this.emitDescription(this.descriptionForType(u)); const indirect = this.isCycleBreakerType(u) ? "indirect " : ""; const [maybeNull, nonNulls] = removeNullFromUnion(u, sortBy); - this.emitBlockWithAccess([indirect, "enum ", unionName, this.getProtocolString("enum")], () => { - this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => { - this.emitLine("case ", name, "(", this.swiftType(t), ")"); - }); - if (maybeNull !== null) { - this.emitLine("case ", this.nameForUnionMember(u, maybeNull)); - } + this.emitBlockWithAccess( + [indirect, "enum ", unionName, this.getProtocolString("enum")], + () => { + this.forEachUnionMember( + u, + nonNulls, + "none", + null, + (name, t) => { + this.emitLine( + "case ", + name, + "(", + this.swiftType(t), + ")", + ); + }, + ); + if (maybeNull !== null) { + this.emitLine( + "case ", + this.nameForUnionMember(u, maybeNull), + ); + } - if (!this._options.justTypes) { - this.ensureBlankLine(); - this.emitBlockWithAccess("init(from decoder: Decoder) throws", () => { - this.emitLine("let container = try decoder.singleValueContainer()"); - const boolMember = u.findMember("bool"); - if (boolMember !== undefined) renderUnionCase(boolMember); - const integerMember = u.findMember("integer"); - if (integerMember !== undefined) renderUnionCase(integerMember); - for (const t of nonNulls) { - if (t.kind === "bool" || t.kind === "integer") continue; - renderUnionCase(t); - } + if (!this._options.justTypes) { + this.ensureBlankLine(); + this.emitBlockWithAccess( + "init(from decoder: Decoder) throws", + () => { + this.emitLine( + "let container = try decoder.singleValueContainer()", + ); + const boolMember = u.findMember("bool"); + if (boolMember !== undefined) + renderUnionCase(boolMember); + const integerMember = u.findMember("integer"); + if (integerMember !== undefined) + renderUnionCase(integerMember); + for (const t of nonNulls) { + 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"); - }); - } + if (maybeNull !== null) { + this.emitBlock( + "if container.decodeNil()", + () => { + this.emitLine( + "self = .", + this.nameForUnionMember( + u, + maybeNull, + ), + ); + this.emitLine("return"); + }, + ); + } - this.emitDecodingError(unionName); - }); - this.ensureBlankLine(); - this.emitBlockWithAccess("func encode(to encoder: Encoder) throws", () => { - this.emitLine("var container = encoder.singleValueContainer()"); - this.emitLine("switch self {"); - this.forEachUnionMember(u, nonNulls, "none", null, (name, _) => { - this.emitLine("case .", name, "(let x):"); - this.indent(() => this.emitLine("try container.encode(x)")); - }); - if (maybeNull !== null) { - this.emitLine("case .", this.nameForUnionMember(u, maybeNull), ":"); - this.indent(() => this.emitLine("try container.encodeNil()")); - } + this.emitDecodingError(unionName); + }, + ); + this.ensureBlankLine(); + this.emitBlockWithAccess( + "func encode(to encoder: Encoder) throws", + () => { + this.emitLine( + "var container = encoder.singleValueContainer()", + ); + this.emitLine("switch self {"); + this.forEachUnionMember( + u, + nonNulls, + "none", + null, + (name, _) => { + this.emitLine("case .", name, "(let x):"); + this.indent(() => + this.emitLine( + "try container.encode(x)", + ), + ); + }, + ); + if (maybeNull !== null) { + this.emitLine( + "case .", + this.nameForUnionMember(u, maybeNull), + ":", + ); + this.indent(() => + this.emitLine("try container.encodeNil()"), + ); + } - this.emitLine("}"); - }); - } - }); + this.emitLine("}"); + }, + ); + } + }, + ); this.endFile(); } - private emitTopLevelMapAndArrayConvenienceInitializerExtensions(t: Type, name: Name): void { + private emitTopLevelMapAndArrayConvenienceInitializerExtensions( + t: Type, + name: Name, + ): void { let extensionSource: Sourcelike; if (t instanceof ArrayType) { extensionSource = ["Array where Element == ", name, ".Element"]; } else if (t instanceof MapType) { - extensionSource = ["Dictionary where Key == String, Value == ", this.swiftType(t.values)]; + extensionSource = [ + "Dictionary where Key == String, Value == ", + this.swiftType(t.values), + ]; } else { return; } this.emitBlockWithAccess(["extension ", extensionSource], () => { this.emitBlock(["init(data: Data) throws"], () => { - this.emitLine("self = try newJSONDecoder().decode(", name, ".self, from: data)"); + this.emitLine( + "self = try newJSONDecoder().decode(", + name, + ".self, from: data)", + ); }); 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("try self.init(data: data)"); - }); + 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("try self.init(data: data)"); + }, + ); this.ensureBlankLine(); this.emitBlock("init(fromURL url: URL) throws", () => { this.emitLine("try self.init(data: try Data(contentsOf: url))"); @@ -779,9 +1090,14 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.emitLine("return try newJSONEncoder().encode(self)"); }); this.ensureBlankLine(); - this.emitBlock("func jsonString(encoding: String.Encoding = .utf8) throws -> String?", () => { - this.emitLine("return String(data: try self.jsonData(), encoding: encoding)"); - }); + this.emitBlock( + "func jsonString(encoding: String.Encoding = .utf8) throws -> String?", + () => { + this.emitLine( + "return String(data: try self.jsonData(), encoding: encoding)", + ); + }, + ); }); } @@ -791,7 +1107,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); name, '.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ', name, - '"))' + '"))', ); } @@ -803,19 +1119,31 @@ 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.forEachTopLevel( + "leading-and-interposing", + (t: Type, name: 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.emitMark( + "Helper functions for creating encoders and decoders", + true, + ); this.ensureBlankLine(); this.emitNewEncoderDecoder(); } @@ -834,9 +1162,16 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.emitMark("Encode/decode helpers", true); this.ensureBlankLine(); if (this._options.objcSupport) { - this.emitLine(this.objcMembersDeclaration, this.accessLevel, "class JSONNull: NSObject, Codable {"); + this.emitLine( + this.objcMembersDeclaration, + this.accessLevel, + "class JSONNull: NSObject, Codable {", + ); } else { - this.emitLine(this.accessLevel, "class JSONNull: Codable, Hashable {"); + this.emitLine( + this.accessLevel, + "class JSONNull: Codable, Hashable {", + ); } this.ensureBlankLine(); @@ -905,7 +1240,11 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.ensureBlankLine(); if (this._options.objcSupport) { - this.emitLine(this.objcMembersDeclaration, this.accessLevel, "class JSONAny: NSObject, Codable {"); + this.emitLine( + this.objcMembersDeclaration, + this.accessLevel, + "class JSONAny: NSObject, Codable {", + ); } else { this.emitLine(this.accessLevel, "class JSONAny: Codable {"); } @@ -1117,23 +1456,29 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); ": ", this.swiftPropertyType(p), "? = nil", - position !== "only" && position !== "last" ? "," : "" + position !== "only" && position !== "last" ? "," : "", ); }); }); this.emitBlock([") -> ", className], () => { this.emitLine("return ", className, "("); this.indent(() => { - this.forEachClassProperty(c, "none", (name, _, _p, position) => { - this.emitLine( - name, - ": ", - name, - " ?? self.", - name, - position !== "only" && position !== "last" ? "," : "" - ); - }); + this.forEachClassProperty( + c, + "none", + (name, _, _p, position) => { + this.emitLine( + name, + ": ", + name, + " ?? self.", + name, + position !== "only" && position !== "last" + ? "," + : "", + ); + }, + ); }); this.emitLine(")"); }); @@ -1150,9 +1495,12 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); this.forEachNamedType( "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) + (c: ClassType, className: Name) => + this.renderClassDefinition(c, className), + (e: EnumType, enumName: Name) => + this.renderEnumDefinition(e, enumName), + (u: UnionType, unionName: Name) => + this.renderUnionDefinition(u, unionName), ); if (!this._options.justTypes) { @@ -1163,8 +1511,7 @@ encoder.dateEncodingStrategy = .formatted(formatter)`); private emitAlamofireExtension(): void { this.ensureBlankLine(); this.emitBlockWithAccess("extension DataRequest", () => { - this - .emitMultiline(`fileprivate func decodableResponseSerializer() -> DataResponseSerializer { + this.emitMultiline(`fileprivate func decodableResponseSerializer() -> DataResponseSerializer { return DataResponseSerializer { _, response, data, error in guard error == nil else { return .failure(error!) } @@ -1189,11 +1536,13 @@ 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/Swift/constants.ts b/packages/quicktype-core/src/language/Swift/constants.ts index 4a8c4ee2..2298d1bd 100644 --- a/packages/quicktype-core/src/language/Swift/constants.ts +++ b/packages/quicktype-core/src/language/Swift/constants.ts @@ -97,5 +97,5 @@ export const keywords = [ "convertDict", "convertDouble", "jsonString", - "jsonData" + "jsonData", ] as const; diff --git a/packages/quicktype-core/src/language/Swift/language.ts b/packages/quicktype-core/src/language/Swift/language.ts index 6d9c81d5..d40d0af1 100644 --- a/packages/quicktype-core/src/language/Swift/language.ts +++ b/packages/quicktype-core/src/language/Swift/language.ts @@ -1,72 +1,115 @@ -import { type DateTimeRecognizer } from "../../DateTime"; -import { type RenderContext } from "../../Renderer"; -import { BooleanOption, EnumOption, StringOption, getOptionValues } from "../../RendererOptions"; +import type { DateTimeRecognizer } from "../../DateTime"; +import type { RenderContext } from "../../Renderer"; +import { + BooleanOption, + EnumOption, + 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 "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } 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), + 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" + "secondary", ), alamofire: new BooleanOption("alamofire", "Alamofire extensions", false), - namedTypePrefix: new StringOption("type-prefix", "Prefix for type names", "PREFIX", "", "secondary"), + 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, } as const, - "struct" + "struct", + ), + mutableProperties: new BooleanOption( + "mutable-properties", + "Use var instead of let for object properties", + false, ), - 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 + normal: false, } as const, "dense", - "secondary" + "secondary", + ), + linux: new BooleanOption( + "support-linux", + "Support Linux", + false, + "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, + ), + sendable: new BooleanOption( + "sendable", + "Mark generated models as Sendable", + 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 + false, ), accessLevel: new EnumOption( "access-level", "Access level", { internal: "internal", - public: "public" + public: "public", } as const, "internal", - "secondary" + "secondary", ), protocol: new EnumOption( "protocol", @@ -74,20 +117,22 @@ export const swiftOptions = { { none: { equatable: false, hashable: false }, equatable: { equatable: true, hashable: false }, - hashable: { equatable: false, hashable: true } + hashable: { equatable: false, hashable: true }, } as const, "none", - "secondary" - ) + "secondary", + ), }; export const swiftLanguageConfig = { displayName: "Swift", names: ["swift", "swift4"], - extension: "swift" + extension: "swift", } as const; -export class SwiftTargetLanguage extends TargetLanguage { +export class SwiftTargetLanguage extends TargetLanguage< + typeof swiftLanguageConfig +> { public constructor() { super(swiftLanguageConfig); } @@ -97,7 +142,8 @@ export class SwiftTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); mapping.set("date-time", "date-time"); return mapping; } @@ -110,8 +156,15 @@ export class SwiftTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): SwiftRenderer { + return new SwiftRenderer( + this, + renderContext, + getOptionValues(swiftOptions, untypedOptionValues), + ); } public get dateTimeRecognizer(): DateTimeRecognizer { diff --git a/packages/quicktype-core/src/language/Swift/utils.ts b/packages/quicktype-core/src/language/Swift/utils.ts index ce4e2fa8..ee452517 100644 --- a/packages/quicktype-core/src/language/Swift/utils.ts +++ b/packages/quicktype-core/src/language/Swift/utils.ts @@ -1,6 +1,6 @@ import { DefaultDateTimeRecognizer } from "../../DateTime"; -import { type Name } from "../../Naming"; -import { type ForEachPosition } from "../../Renderer"; +import type { Name } from "../../Naming"; +import type { ForEachPosition } from "../../Renderer"; import { addPrefixIfNecessary, allLowerWordStyle, @@ -15,9 +15,9 @@ import { isPrintable, legalizeCharacters, splitIntoWords, - utf32ConcatMap + utf32ConcatMap, } from "../../support/Strings"; -import { type ClassProperty } from "../../Type"; +import type { ClassProperty } from "../../Type"; export const MAX_SAMELINE_PROPERTIES = 4; @@ -61,7 +61,7 @@ export 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( @@ -72,7 +72,7 @@ export function swiftNameStyle( isUpper ? allUpperWordStyle : allLowerWordStyle, acronymsStyle, "", - isStartCharacter + isStartCharacter, ); return addPrefixIfNecessary(prefix, combined); } @@ -81,4 +81,6 @@ function unicodeEscape(codePoint: number): string { return "\\u{" + intToHex(codePoint, 0) + "}"; } -export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, unicodeEscape)); +export const stringEscape = utf32ConcatMap( + escapeNonPrintableMapper(isPrintable, unicodeEscape), +); diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts index 7ca8d840..f5d117c3 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema/TypeScriptEffectSchemaRenderer.ts @@ -2,9 +2,9 @@ import { arrayIntercalate } from "collection-utils"; 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 type { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; +import type { Sourcelike } from "../../Source"; import { AcronymStyleOptions, acronymStyle } from "../../support/Acronyms"; import { allLowerWordStyle, @@ -14,15 +14,22 @@ import { isLetterOrUnderscore, splitIntoWords, stringEscape, - utf16StringEscape + utf16StringEscape, } 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 type { TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassProperty, + EnumType, + MapType, + type ObjectType, + type Type, +} from "../../Type"; import { matchType } from "../../Type/TypeUtils"; import { legalizeName } from "../JavaScript/utils"; -import { type typeScriptEffectSchemaOptions } from "./language"; +import type { typeScriptEffectSchemaOptions } from "./language"; export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { private emittedObjects = new Set(); @@ -30,7 +37,9 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - private readonly _options: OptionValues + private readonly _options: OptionValues< + typeof typeScriptEffectSchemaOptions + >, ) { super(targetLanguage, renderContext); } @@ -50,27 +59,30 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("types", s => this.nameStyle(s, true)); + return funPrefixNamer("types", (s) => this.nameStyle(s, true)); } protected makeUnionMemberNamer(): Namer { - return funPrefixNamer("properties", s => this.nameStyle(s, true)); + return funPrefixNamer("properties", (s) => this.nameStyle(s, true)); } protected namerForObjectProperty(): Namer { - return funPrefixNamer("properties", s => this.nameStyle(s, true)); + return funPrefixNamer("properties", (s) => this.nameStyle(s, true)); } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); + 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, ";"]; } @@ -87,7 +99,7 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { return ["S.optional(", this.typeMapTypeFor(p.type), ")"]; } - private typeMapTypeFor(t: Type, required: boolean = true): Sourcelike { + private typeMapTypeFor(t: Type, required = true): Sourcelike { if (t.kind === "class" || t.kind === "object" || t.kind === "enum") { const name = this.nameForNamedType(t); if (this.emittedObjects.has(name)) { @@ -99,19 +111,27 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { const match = matchType( t, - _anyType => "S.Any", - _nullType => "S.Null", - _boolType => "S.Boolean", - _integerType => "S.Number", - _doubleType => "S.Number", - _stringType => "S.String", - arrayType => ["S.Array(", this.typeMapTypeFor(arrayType.items, false), ")"], - _classType => panic("Should already be handled."), - _mapType => ["S.Record({ key: S.String, value: ", this.typeMapTypeFor(_mapType.values, false), "})"], - _enumType => panic("Should already be handled."), - unionType => { + (_anyType) => "S.Any", + (_nullType) => "S.Null", + (_boolType) => "S.Boolean", + (_integerType) => "S.Number", + (_doubleType) => "S.Number", + (_stringType) => "S.String", + (arrayType) => [ + "S.Array(", + this.typeMapTypeFor(arrayType.items, false), + ")", + ], + (_classType) => panic("Should already be handled."), + (_mapType) => [ + "S.Record({ key: S.String, value: ", + this.typeMapTypeFor(_mapType.values, false), + "})", + ], + (_enumType) => panic("Should already be handled."), + (unionType) => { const types = Array.from(unionType.getChildren()); - let children: Sourcelike[] = []; + const children: Sourcelike[] = []; let nullable = false; for (const type of types) { if (type.kind === "null") { @@ -125,11 +145,15 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { return ["S.NullOr(", children[0], ")"]; } - return ["S.Union(", ...arrayIntercalate(", ", children), nullable ? ", S.Null)" : ")"]; + return [ + "S.Union(", + ...arrayIntercalate(", ", children), + nullable ? ", S.Null)" : ")", + ]; }, - _transformedStringType => { + (_transformedStringType) => { return "S.String"; - } + }, ); if (required) { @@ -142,10 +166,23 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { private emitObject(name: Name, t: ObjectType): void { 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), ","); + this.emitLine( + `"${utf16StringEscape(jsonName)}"`, + ": ", + this.typeMapTypeForProperty(property), + ",", + ); }); }); this.emitLine("}) {}"); @@ -159,11 +196,17 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { this.indent(() => this.forEachEnumCase(e, "none", (_, jsonName) => { this.emitLine('"', stringEscape(jsonName), '",'); - }) + }), ); this.emitLine(");"); if (!this._options.justSchema) { - this.emitLine("export type ", enumName, " = S.Schema.Type;"); + this.emitLine( + "export type ", + enumName, + " = S.Schema.Type;", + ); } } @@ -173,9 +216,13 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { const recurse = (type: Type): void => { if (type.kind === "object" || type.kind === "class") { names.push(this.nameForNamedType(type)); - this.forEachClassProperty(type as ObjectType, "none", (_, __, prop) => { - recurse(prop.type); - }); + this.forEachClassProperty( + type as ObjectType, + "none", + (_, __, prop) => { + recurse(prop.type); + }, + ); } else if (type instanceof ArrayType) { recurse(type.items); } else if (type instanceof MapType) { @@ -197,9 +244,12 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { protected emitSchemas(): void { this.ensureBlankLine(); - this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => { - this.emitEnum(u, enumName); - }); + this.forEachEnum( + "leading-and-interposing", + (u: EnumType, enumName: Name) => { + this.emitEnum(u, enumName); + }, + ); const order: number[] = []; const mapKey: Name[] = []; @@ -218,11 +268,11 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { const names = this.walkObjectNames(source); // must be behind all these names - names.forEach(name => { + names.forEach((name) => { const depName = name; // find this name's ordinal, if it has already been added - order.forEach(orderItem => { + order.forEach((orderItem) => { const depIndex = orderItem; if (mapKey[depIndex] === depName) { // this is the index of the dependency, so make sure we come after it @@ -236,7 +286,13 @@ export class TypeScriptEffectSchemaRenderer extends ConvenienceRenderer { }); // now emit ordered source - order.forEach(i => this.emitGatheredSource(this.gatherSource(() => this.emitObject(mapKey[i], mapValue[i])))); + order.forEach((i) => + this.emitGatheredSource( + this.gatherSource(() => + this.emitObject(mapKey[i], mapValue[i]), + ), + ), + ); } protected emitSourceStructure(): void { diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts index ea8cf814..555704cf 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema/index.ts @@ -1,2 +1,5 @@ -export { TypeScriptEffectSchemaTargetLanguage, typeScriptEffectSchemaOptions } from "./language"; +export { + TypeScriptEffectSchemaTargetLanguage, + typeScriptEffectSchemaOptions, +} from "./language"; export { TypeScriptEffectSchemaRenderer } from "./TypeScriptEffectSchemaRenderer"; diff --git a/packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts b/packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts index 9d14bf29..d55ecc1b 100644 --- a/packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts +++ b/packages/quicktype-core/src/language/TypeScriptEffectSchema/language.ts @@ -1,21 +1,23 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { BooleanOption, getOptionValues } from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type FixMeOptionsType } from "../../types"; +import type { LanguageName, RendererOptions } from "../../types"; import { TypeScriptEffectSchemaRenderer } from "./TypeScriptEffectSchemaRenderer"; export const typeScriptEffectSchemaOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false) + justSchema: new BooleanOption("just-schema", "Schema only", false), }; export const typeScriptEffectSchemaLanguageConfig = { displayName: "TypeScript Effect Schema", names: ["typescript-effect-schema"], - extension: "ts" + extension: "ts", } as const; -export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage { +export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage< + typeof typeScriptEffectSchemaLanguageConfig +> { public constructor() { super(typeScriptEffectSchemaLanguageConfig); } @@ -24,14 +26,16 @@ export class TypeScriptEffectSchemaTargetLanguage extends TargetLanguage( renderContext: RenderContext, - untypedOptionValues: FixMeOptionsType + untypedOptionValues: RendererOptions, ): TypeScriptEffectSchemaRenderer { return new TypeScriptEffectSchemaRenderer( this, renderContext, - getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues) + getOptionValues(typeScriptEffectSchemaOptions, untypedOptionValues), ); } } diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts index eb469558..02e82aee 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/FlowRenderer.ts @@ -1,8 +1,8 @@ -import { type Name } from "../../Naming"; +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 type { ClassType, EnumType } from "../../Type"; +import type { JavaScriptTypeAnnotations } from "../JavaScript"; import { TypeScriptFlowBaseRenderer } from "./TypeScriptFlowBaseRenderer"; import { tsFlowTypeAnnotations } from "./utils"; diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts index 371aad61..2acc4da2 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptFlowBaseRenderer.ts @@ -1,37 +1,60 @@ 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 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 type { TargetLanguage } from "../../TargetLanguage"; +import { + ArrayType, + type ClassType, + EnumType, + type Type, + UnionType, +} from "../../Type"; import { matchType, nullableFromUnion } from "../../Type/TypeUtils"; -import { JavaScriptRenderer, type JavaScriptTypeAnnotations } from "../JavaScript"; +import { + JavaScriptRenderer, + type JavaScriptTypeAnnotations, +} from "../JavaScript"; -import { type tsFlowOptions } from "./language"; +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 + 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(); + return funPrefixNamer("properties", (s) => + this.nameStyle(s, false), + ); } + + 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; + 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)}"`); } @@ -41,41 +64,52 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { return matchType( t, - _anyType => singleWord("any"), - _nullType => singleWord("null"), - _boolType => singleWord("boolean"), - _integerType => singleWord("number"), - _doubleType => singleWord("number"), - _stringType => singleWord("string"), - arrayType => { + (_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 UnionType && + !this._tsFlowOptions.declareUnions) || arrayType.items instanceof ArrayType ) { return singleWord(["Array<", itemType.source, ">"]); - } else { - return singleWord([parenIfNeeded(itemType), "[]"]); } + + 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))); + (_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)); } + + return singleWord(this.nameForNamedType(unionType)); }, - transformedStringType => { + (transformedStringType) => { if (transformedStringType.kind === "date-time") { return singleWord("Date"); } return singleWord("string"); - } + }, ); } @@ -91,18 +125,28 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { propertyName = modifySource(quotePropertyName, name); if (this._tsFlowOptions.readonly) { - propertyName = modifySource(_propertyName => "readonly " + _propertyName, propertyName); + propertyName = modifySource( + (_propertyName) => `readonly ${_propertyName}`, + propertyName, + ); } return [ [propertyName, p.isOptional ? "?" : "", ": "], - [this.sourceFor(t).source, ";"] + [this.sourceFor(t).source, ";"], ]; }); const additionalProperties = c.getAdditionalProperties(); if (additionalProperties) { - this.emitTable([["[property: string]", ": ", this.sourceFor(additionalProperties).source, ";"]]); + this.emitTable([ + [ + "[property: string]", + ": ", + this.sourceFor(additionalProperties).source, + ";", + ], + ]); } } @@ -118,7 +162,12 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { this.emitDescription(this.descriptionForType(u)); - const children = multiWord(" | ", ...Array.from(u.getChildren()).map(c => parenIfNeeded(this.sourceFor(c)))); + const children = multiWord( + " | ", + ...Array.from(u.getChildren()).map((c) => + parenIfNeeded(this.sourceFor(c)), + ), + ); this.emitLine("export type ", unionName, " = ", children.source, ";"); } @@ -138,7 +187,7 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { "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), ); } @@ -148,14 +197,30 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } 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]; + 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]; + const returnType = + this._tsFlowOptions.rawType === "json" ? "string" : "any"; + return [ + "function ", + camelCaseName, + "ToJson(value: ", + this.sourceFor(t).source, + "): ", + returnType, + ]; } protected get moduleLine(): string | undefined { @@ -163,7 +228,10 @@ export abstract class TypeScriptFlowBaseRenderer extends JavaScriptRenderer { } protected get castFunctionLines(): [string, string] { - return ["function cast(val: any, typ: any): T", "function uncast(val: T, typ: any): any"]; + return [ + "function cast(val: any, typ: any): T", + "function uncast(val: T, typ: any): any", + ]; } protected get typeAnnotations(): JavaScriptTypeAnnotations { diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts index 42a79b32..82d27248 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/TypeScriptRenderer.ts @@ -1,9 +1,9 @@ -import { type Name } from "../../Naming"; +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 type { ClassType, EnumType, Type } from "../../Type"; import { isNamedType } from "../../Type/TypeUtils"; -import { type JavaScriptTypeAnnotations } from "../JavaScript"; +import type { JavaScriptTypeAnnotations } from "../JavaScript"; import { TypeScriptFlowBaseRenderer } from "./TypeScriptFlowBaseRenderer"; import { tsFlowTypeAnnotations } from "./utils"; @@ -14,14 +14,30 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { } 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]; + 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]; + const returnType = + this._tsFlowOptions.rawType === "json" ? "string" : "any"; + return [ + "public static ", + camelCaseName, + "ToJson(value: ", + this.sourceFor(t).source, + "): ", + returnType, + ]; } protected get moduleLine(): string | undefined { @@ -43,9 +59,13 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { (_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 { @@ -56,7 +76,7 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { if (this._tsFlowOptions.preferUnions) { let items = ""; - e.cases.forEach(item => { + e.cases.forEach((item) => { if (items === "") { items += `"${utf16StringEscape(item)}"`; return; @@ -82,7 +102,7 @@ export class TypeScriptRenderer extends TypeScriptFlowBaseRenderer { "", () => { this.emitClassBlockBody(c); - } + }, ); } } diff --git a/packages/quicktype-core/src/language/TypeScriptFlow/index.ts b/packages/quicktype-core/src/language/TypeScriptFlow/index.ts index 681acaa3..42d51fa3 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/index.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/index.ts @@ -1,3 +1,7 @@ export { FlowRenderer } from "./FlowRenderer"; export { TypeScriptRenderer } from "./TypeScriptRenderer"; -export { FlowTargetLanguage, TypeScriptTargetLanguage, tsFlowOptions } from "./language"; +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 index 909fec0b..1a5bdde8 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/language.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/language.ts @@ -1,9 +1,12 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { BooleanOption, getOptionValues } from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; -import { type StringTypeMapping } from "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } from "../../types"; import { javaScriptOptions } from "../JavaScript"; import { FlowRenderer } from "./FlowRenderer"; @@ -11,25 +14,43 @@ 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), + 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 + false, ), - readonly: new BooleanOption("readonly", "Use readonly type members", false) + readonly: new BooleanOption("readonly", "Use readonly type members", false), }); export const typeScriptLanguageConfig = { displayName: "TypeScript", names: ["typescript", "ts", "tsx"], - extension: "ts" + extension: "ts", } as const; -export class TypeScriptTargetLanguage extends TargetLanguage { +export class TypeScriptTargetLanguage extends TargetLanguage< + typeof typeScriptLanguageConfig +> { public constructor() { super(typeScriptLanguageConfig); } @@ -39,7 +60,8 @@ export class TypeScriptTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); mapping.set("date-time", dateTimeType); @@ -54,18 +76,27 @@ export class TypeScriptTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): TypeScriptRenderer { + return new TypeScriptRenderer( + this, + renderContext, + getOptionValues(tsFlowOptions, untypedOptionValues), + ); } } export const flowLanguageConfig = { displayName: "Flow", names: ["flow"], - extension: "js" + extension: "js", } as const; -export class FlowTargetLanguage extends TargetLanguage { +export class FlowTargetLanguage extends TargetLanguage< + typeof flowLanguageConfig +> { public constructor() { super(flowLanguageConfig); } @@ -75,7 +106,8 @@ export class FlowTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); const dateTimeType = "date-time"; mapping.set("date", dateTimeType); mapping.set("date-time", dateTimeType); @@ -90,7 +122,14 @@ export class FlowTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): 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 index b15b7eb1..0d01ca9c 100644 --- a/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts +++ b/packages/quicktype-core/src/language/TypeScriptFlow/utils.ts @@ -8,7 +8,7 @@ export const tsFlowTypeAnnotations = { anyMap: ": { [k: string]: any }", string: ": string", stringArray: ": string[]", - boolean: ": boolean" + boolean: ": boolean", }; export function quotePropertyName(original: string): string { diff --git a/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts b/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts index 7a6f8560..bcd9aa4c 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod/TypeScriptZodRenderer.ts @@ -2,9 +2,9 @@ import { arrayIntercalate } from "collection-utils"; 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 type { RenderContext } from "../../Renderer"; +import type { OptionValues } from "../../RendererOptions"; +import type { Sourcelike } from "../../Source"; import { AcronymStyleOptions, acronymStyle } from "../../support/Acronyms"; import { allLowerWordStyle, @@ -14,10 +14,10 @@ import { isLetterOrUnderscore, splitIntoWords, stringEscape, - utf16StringEscape + utf16StringEscape, } from "../../support/Strings"; import { panic } from "../../support/Support"; -import { type TargetLanguage } from "../../TargetLanguage"; +import type { TargetLanguage } from "../../TargetLanguage"; import { ArrayType, type ClassProperty, @@ -25,18 +25,18 @@ import { type EnumType, ObjectType, SetOperationType, - type Type + type Type, } from "../../Type"; import { matchType } from "../../Type/TypeUtils"; import { legalizeName } from "../JavaScript/utils"; -import { type typeScriptZodOptions } from "./language"; +import type { typeScriptZodOptions } from "./language"; export class TypeScriptZodRenderer extends ConvenienceRenderer { public constructor( targetLanguage: TargetLanguage, renderContext: RenderContext, - protected readonly _options: OptionValues + protected readonly _options: OptionValues, ) { super(targetLanguage, renderContext); } @@ -56,27 +56,30 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { upper ? (s): string => capitalize(acronyms(s)) : allLowerWordStyle, acronyms, "", - isLetterOrUnderscore + isLetterOrUnderscore, ); } protected makeNamedTypeNamer(): Namer { - return funPrefixNamer("types", s => this.nameStyle(s, true)); + return funPrefixNamer("types", (s) => this.nameStyle(s, true)); } protected makeUnionMemberNamer(): Namer { - return funPrefixNamer("properties", s => this.nameStyle(s, true)); + return funPrefixNamer("properties", (s) => this.nameStyle(s, true)); } protected namerForObjectProperty(): Namer { - return funPrefixNamer("properties", s => this.nameStyle(s, true)); + return funPrefixNamer("properties", (s) => this.nameStyle(s, true)); } protected makeEnumCaseNamer(): Namer { - return funPrefixNamer("enum-cases", s => this.nameStyle(s, false)); + 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, ";"]; } @@ -90,36 +93,44 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { return p.isOptional ? [typeMap, ".optional()"] : typeMap; } - protected typeMapTypeFor(t: Type, required: boolean = true): Sourcelike { + protected typeMapTypeFor(t: Type, required = true): Sourcelike { if (["class", "object", "enum"].includes(t.kind)) { return [this.nameForNamedType(t), "Schema"]; } const match = matchType( t, - _anyType => "z.any()", - _nullType => "z.null()", - _boolType => "z.boolean()", - _integerType => "z.number()", - _doubleType => "z.number()", - _stringType => "z.string()", - arrayType => ["z.array(", this.typeMapTypeFor(arrayType.items, false), ")"], - _classType => panic("Should already be handled."), - _mapType => ["z.record(z.string(), ", this.typeMapTypeFor(_mapType.values, false), ")"], - _enumType => panic("Should already be handled."), - unionType => { - const children = Array.from(unionType.getChildren()).map((type: Type) => - this.typeMapTypeFor(type, false) + (_anyType) => "z.any()", + (_nullType) => "z.null()", + (_boolType) => "z.boolean()", + (_integerType) => "z.number()", + (_doubleType) => "z.number()", + (_stringType) => "z.string()", + (arrayType) => [ + "z.array(", + this.typeMapTypeFor(arrayType.items, false), + ")", + ], + (_classType) => panic("Should already be handled."), + (_mapType) => [ + "z.record(z.string(), ", + this.typeMapTypeFor(_mapType.values, false), + ")", + ], + (_enumType) => panic("Should already be handled."), + (unionType) => { + const children = Array.from(unionType.getChildren()).map( + (type: Type) => this.typeMapTypeFor(type, false), ); return ["z.union([", ...arrayIntercalate(", ", children), "])"]; }, - _transformedStringType => { + (_transformedStringType) => { if (_transformedStringType.kind === "date-time") { return "z.coerce.date()"; } return "z.string()"; - } + }, ); if (required) { @@ -134,12 +145,23 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { this.emitLine("\nexport const ", name, "Schema = ", "z.object({"); this.indent(() => { this.forEachClassProperty(t, "none", (_, jsonName, property) => { - this.emitLine(`"${utf16StringEscape(jsonName)}"`, ": ", this.typeMapTypeForProperty(property), ","); + this.emitLine( + `"${utf16StringEscape(jsonName)}"`, + ": ", + this.typeMapTypeForProperty(property), + ",", + ); }); }); this.emitLine("});"); if (!this._options.justSchema) { - this.emitLine("export type ", name, " = z.infer;"); + this.emitLine( + "export type ", + name, + " = z.infer;", + ); } } @@ -150,11 +172,17 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { this.indent(() => this.forEachEnumCase(e, "none", (_, jsonName) => { this.emitLine('"', stringEscape(jsonName), '",'); - }) + }), ); this.emitLine("]);"); if (!this._options.justSchema) { - this.emitLine("export type ", enumName, " = z.infer;"); + this.emitLine( + "export type ", + enumName, + " = z.infer;", + ); } } @@ -166,15 +194,19 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { * these are ignored. */ private static extractUnderlyingTyperefs(type: Type): number[] { - let typeRefs: number[] = []; + const typeRefs: number[] = []; // Ignore enums and primitives - if (!type.isPrimitive() && type.kind != "enum") { + 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 if (type instanceof SetOperationType) { - (type as SetOperationType).members.forEach(member => { + (type as SetOperationType).members.forEach((member) => { // recurse as the underlying type could itself be a union, instersection or array etc. - typeRefs.push(...TypeScriptZodRenderer.extractUnderlyingTyperefs(member)); + typeRefs.push( + ...TypeScriptZodRenderer.extractUnderlyingTyperefs( + member, + ), + ); }); } @@ -183,7 +215,11 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { const addType = (type as ObjectType).getAdditionalProperties(); if (addType) { // recurse as the underlying type could itself be a union, instersection or array etc. - typeRefs.push(...TypeScriptZodRenderer.extractUnderlyingTyperefs(addType)); + typeRefs.push( + ...TypeScriptZodRenderer.extractUnderlyingTyperefs( + addType, + ), + ); } } @@ -192,7 +228,11 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { const itemsType = (type as ArrayType).items; if (itemsType) { // recurse as the underlying type could itself be a union, instersection or array etc. - typeRefs.push(...TypeScriptZodRenderer.extractUnderlyingTyperefs(itemsType)); + typeRefs.push( + ...TypeScriptZodRenderer.extractUnderlyingTyperefs( + itemsType, + ), + ); } } @@ -208,9 +248,12 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { protected emitSchemas(): void { this.ensureBlankLine(); - this.forEachEnum("leading-and-interposing", (u: EnumType, enumName: Name) => { - this.emitEnum(u, enumName); - }); + this.forEachEnum( + "leading-and-interposing", + (u: EnumType, enumName: Name) => { + this.emitEnum(u, enumName); + }, + ); // All children must be defined before this type to avoid forward references in generated code // Build a model that will tell us if a referenced type has been defined then make multiple @@ -231,8 +274,10 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { const children = type.getChildren(); let childTypeRefs: number[] = []; - children.forEach(child => { - childTypeRefs = childTypeRefs.concat(TypeScriptZodRenderer.extractUnderlyingTyperefs(child)); + children.forEach((child) => { + childTypeRefs = childTypeRefs.concat( + TypeScriptZodRenderer.extractUnderlyingTyperefs(child), + ); }); mapChildTypeRefs.push(childTypeRefs); }); @@ -249,12 +294,12 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { const MAX_PASSES = 999; let passNum = 0; do { - indices.forEach(index => { + indices.forEach((index) => { // must be behind all these children const childTypeRefs = mapChildTypeRefs[index]; let foundAllChildren = true; - childTypeRefs.forEach(childRef => { + childTypeRefs.forEach((childRef) => { // defensive: first check if there is a definition for the referenced type (there should be) if (mapTypeRef.includes(childRef)) { let found = false; @@ -274,7 +319,8 @@ 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, ); } }); @@ -295,13 +341,19 @@ export class TypeScriptZodRenderer extends ConvenienceRenderer { // giving up order.push(...deferredIndices); console.warn( - "Exceeded maximum number of passes when determining output order, output may contain forward references" + "Exceeded maximum number of passes when determining output order, output may contain forward references", ); } } while (indices.length > 0 && passNum <= MAX_PASSES); // now emit ordered source - order.forEach(i => this.emitGatheredSource(this.gatherSource(() => this.emitObject(mapName[i], mapType[i])))); + order.forEach((i) => + this.emitGatheredSource( + this.gatherSource(() => + this.emitObject(mapName[i], mapType[i]), + ), + ), + ); } protected emitSourceStructure(): void { diff --git a/packages/quicktype-core/src/language/TypeScriptZod/language.ts b/packages/quicktype-core/src/language/TypeScriptZod/language.ts index 88e2a9a8..37e5a2e7 100644 --- a/packages/quicktype-core/src/language/TypeScriptZod/language.ts +++ b/packages/quicktype-core/src/language/TypeScriptZod/language.ts @@ -1,23 +1,28 @@ -import { type RenderContext } from "../../Renderer"; +import type { RenderContext } from "../../Renderer"; import { BooleanOption, getOptionValues } from "../../RendererOptions"; import { TargetLanguage } from "../../TargetLanguage"; -import { type PrimitiveStringTypeKind, type TransformedStringTypeKind } from "../../Type"; -import { type StringTypeMapping } from "../../Type/TypeBuilderUtils"; -import { type FixMeOptionsType } from "../../types"; +import type { + PrimitiveStringTypeKind, + TransformedStringTypeKind, +} from "../../Type"; +import type { StringTypeMapping } from "../../Type/TypeBuilderUtils"; +import type { LanguageName, RendererOptions } from "../../types"; import { TypeScriptZodRenderer } from "./TypeScriptZodRenderer"; export const typeScriptZodOptions = { - justSchema: new BooleanOption("just-schema", "Schema only", false) + justSchema: new BooleanOption("just-schema", "Schema only", false), }; export const typeScriptZodLanguageConfig = { displayName: "TypeScript Zod", names: ["typescript-zod"], - extension: "ts" + extension: "ts", } as const; -export class TypeScriptZodTargetLanguage extends TargetLanguage { +export class TypeScriptZodTargetLanguage extends TargetLanguage< + typeof typeScriptZodLanguageConfig +> { public constructor() { super(typeScriptZodLanguageConfig); } @@ -27,7 +32,8 @@ export class TypeScriptZodTargetLanguage extends TargetLanguage = new Map(); + const mapping: Map = + new Map(); const dateTimeType = "date-time"; mapping.set("date-time", dateTimeType); return mapping; @@ -37,11 +43,14 @@ export class TypeScriptZodTargetLanguage extends TargetLanguage( + renderContext: RenderContext, + untypedOptionValues: RendererOptions, + ): TypeScriptZodRenderer { return new TypeScriptZodRenderer( this, renderContext, - getOptionValues(typeScriptZodOptions, untypedOptionValues) + getOptionValues(typeScriptZodOptions, untypedOptionValues), ); } } diff --git a/packages/quicktype-core/src/language/index.ts b/packages/quicktype-core/src/language/index.ts index ee9515c3..38bac8e4 100644 --- a/packages/quicktype-core/src/language/index.ts +++ b/packages/quicktype-core/src/language/index.ts @@ -25,6 +25,10 @@ export * from "./TypeScriptFlow"; export * from "./TypeScriptEffectSchema"; export * from "./TypeScriptZod"; -export { all as defaultTargetLanguages, languageNamed, isLanguageName } from "./All"; +export { + all as defaultTargetLanguages, + languageNamed, + isLanguageName, +} from "./All"; export type { LanguageName, LanguageDisplayName } from "./types"; export type { RendererOptions } from "./options.types"; diff --git a/packages/quicktype-core/src/language/options.types.ts b/packages/quicktype-core/src/language/options.types.ts index c0addc16..d3fa7d5a 100644 --- a/packages/quicktype-core/src/language/options.types.ts +++ b/packages/quicktype-core/src/language/options.types.ts @@ -3,13 +3,18 @@ import type { OptionMap } from "../RendererOptions"; import type { LanguageName, LanguageNameMap } from "./types"; export type LanguageRawOptionMap = Readonly<{ - [Lang in keyof LanguageNameMap]: ReturnType; + [Lang in keyof LanguageNameMap]: ReturnType< + LanguageNameMap[Lang]["getOptions"] + >; }>; export type LanguageOptionMap = Readonly<{ [Lang in keyof LanguageRawOptionMap]: OptionMap; }>; -export type RendererOptions = { +export type RendererOptions< + Lang extends LanguageName = LanguageName, + Options = LanguageOptionMap[Lang], +> = { -readonly [K in keyof Options]: Options[K]; }; diff --git a/packages/quicktype-core/src/language/types.ts b/packages/quicktype-core/src/language/types.ts index 1a685e62..46af973b 100644 --- a/packages/quicktype-core/src/language/types.ts +++ b/packages/quicktype-core/src/language/types.ts @@ -1,11 +1,14 @@ -import { type TargetLanguage } from "../TargetLanguage"; +import type { TargetLanguage } from "../TargetLanguage"; -import { type all } from "./All"; +import type { all } from "./All"; type AllLanguages = (typeof all)[number]; -export type LanguageDisplayName = Language["displayName"]; -export type LanguageName = Language["names"][number]; +export type LanguageDisplayName< + Language extends TargetLanguage = AllLanguages, +> = Language["displayName"]; +export type LanguageName = + Language["names"][number]; export type LanguageDisplayNameMap = { [Language in AllLanguages as LanguageDisplayName]: Language; diff --git a/packages/quicktype-core/src/rewrites/CombineClasses.ts b/packages/quicktype-core/src/rewrites/CombineClasses.ts index 30d58ebf..5c9562a8 100644 --- a/packages/quicktype-core/src/rewrites/CombineClasses.ts +++ b/packages/quicktype-core/src/rewrites/CombineClasses.ts @@ -1,10 +1,18 @@ -import { type GraphRewriteBuilder } from "../GraphRewriting"; -import { type RunContext } from "../Run"; +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/Type"; -import { type TypeGraph } from "../Type/TypeGraph"; -import { type TypeRef } from "../Type/TypeRef"; -import { combineTypeAttributesOfTypes, nonNullTypeCases } from "../Type/TypeUtils"; +import { + type ClassProperty, + ClassType, + type Type, + setOperationCasesEqual, +} from "../Type/Type"; +import type { TypeGraph } from "../Type/TypeGraph"; +import type { TypeRef } from "../Type/TypeRef"; +import { + combineTypeAttributesOfTypes, + nonNullTypeCases, +} from "../Type/TypeUtils"; import { unifyTypes, unionBuilderForUnification } from "../UnifyClasses"; const REQUIRED_OVERLAP = 3 / 4; @@ -17,11 +25,20 @@ 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 { - return setOperationCasesEqual(s1, s2, true, (a, b) => a.structurallyCompatible(b, true)); +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) { @@ -29,7 +46,10 @@ function canBeCombined(c1: ClassType, c2: ClassType, onlyWithSameProperties: boo return false; } } else { - if (p1.size < p2.size * REQUIRED_OVERLAP || p2.size < p1.size * REQUIRED_OVERLAP) { + if ( + p1.size < p2.size * REQUIRED_OVERLAP || + p2.size < p1.size * REQUIRED_OVERLAP + ) { return false; } } @@ -66,15 +86,19 @@ function canBeCombined(c1: ClassType, c2: ClassType, onlyWithSameProperties: boo if (faults > maxFaults) return false; for (const name of commonProperties) { - let ts = smaller.get(name); - let tl = larger.get(name); + const ts = smaller.get(name); + const tl = larger.get(name); 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)) { + if ( + tsCases.size > 0 && + tlCases.size > 0 && + !typeSetsCanBeCombined(tsCases, tlCases) + ) { return false; } } @@ -82,7 +106,11 @@ function canBeCombined(c1: ClassType, c2: ClassType, onlyWithSameProperties: boo 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); @@ -104,10 +132,12 @@ function tryAddToClique(c: ClassType, clique: Clique, onlyWithSameProperties: bo 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) + const classCandidates = Array.from( + graph.allNamedTypesSeparated().objects, + ).filter( + (o) => o instanceof ClassType && (includeFixedClasses || !o.isFixed), ) as ClassType[]; const cliques: Clique[] = []; @@ -134,7 +164,9 @@ function findSimilarityCliques( cliques[cliqueIndex] = tmp; } - return cliques.map(clique => clique.members).filter(cl => cl.length > 1); + return cliques + .map((clique) => clique.members) + .filter((cl) => cl.length > 1); } export function combineClasses( @@ -143,16 +175,16 @@ export function combineClasses( 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( clique: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { assert(clique.size > 0, "Clique can't be empty"); const attributes = combineTypeAttributesOfTypes("union", clique); @@ -162,7 +194,7 @@ export function combineClasses( builder, unionBuilderForUnification(builder, false, false, conflateNumbers), conflateNumbers, - forwardingRef + forwardingRef, ); } @@ -172,6 +204,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 a1ca3985..47aab269 100644 --- a/packages/quicktype-core/src/rewrites/ExpandStrings.ts +++ b/packages/quicktype-core/src/rewrites/ExpandStrings.ts @@ -6,17 +6,17 @@ import { mapFilter, setIntersect, setIsSuperset, - setUnion + setUnion, } from "collection-utils"; import { StringTypes } from "../attributes/StringTypes"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; -import { type RunContext } from "../Run"; +import type { GraphRewriteBuilder } from "../GraphRewriting"; +import type { RunContext } from "../Run"; import { assert, defined } from "../support/Support"; -import { type PrimitiveType } from "../Type/Type"; -import { type TypeGraph } from "../Type/TypeGraph"; -import { type TypeRef } from "../Type/TypeRef"; +import type { PrimitiveType } from "../Type/Type"; +import type { TypeGraph } from "../Type/TypeGraph"; +import type { TypeRef } from "../Type/TypeRef"; import { stringTypesForType } from "../Type/TypeUtils"; const MIN_LENGTH_FOR_ENUM = 10; @@ -32,15 +32,19 @@ interface EnumInfo { } function isOwnEnum({ numValues, cases }: EnumInfo): boolean { - return numValues >= MIN_LENGTH_FOR_ENUM && cases.size < Math.sqrt(numValues); + return ( + numValues >= MIN_LENGTH_FOR_ENUM && cases.size < Math.sqrt(numValues) + ); } function enumCasesOverlap( newCases: ReadonlySet, existingCases: ReadonlySet, - newAreSubordinate: boolean + newAreSubordinate: boolean, ): boolean { - const smaller = newAreSubordinate ? newCases.size : Math.min(newCases.size, existingCases.size); + const smaller = newAreSubordinate + ? newCases.size + : Math.min(newCases.size, existingCases.size); const overlap = setIntersect(newCases, existingCases).size; return overlap >= smaller * REQUIRED_OVERLAP; } @@ -49,15 +53,22 @@ 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 { const stringTypes = stringTypesForType(t); - const mappedStringTypes = stringTypes.applyStringTypeMapping(stringTypeMapping); + const mappedStringTypes = + stringTypes.applyStringTypeMapping(stringTypeMapping); if (!mappedStringTypes.isRestricted) return undefined; const cases = defined(mappedStringTypes.cases); @@ -69,7 +80,10 @@ 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; } @@ -88,8 +102,13 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum // 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)); + function findOverlap( + newCases: ReadonlySet, + newAreSubordinate: boolean, + ): number { + return enumSets.findIndex((s) => + enumCasesOverlap(newCases, s, newAreSubordinate), + ); } // First, make case sets for all the enums that stand on their own. If @@ -145,16 +164,24 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum function replaceString( group: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { assert(group.size === 1); const t = defined(iterableFirst(group)); const stringTypes = stringTypesForType(t); - const attributes = mapFilter(t.getAttributes(), a => a !== stringTypes); - const mappedStringTypes = stringTypes.applyStringTypeMapping(stringTypeMapping); + const attributes = mapFilter( + t.getAttributes(), + (a) => a !== stringTypes, + ); + const mappedStringTypes = + stringTypes.applyStringTypeMapping(stringTypeMapping); if (!mappedStringTypes.isRestricted) { - return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); + return builder.getStringType( + attributes, + StringTypes.unrestricted, + forwardingRef, + ); } const setMatches = inference === "all" ? areEqual : setIsSuperset; @@ -163,11 +190,19 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum const cases = defined(mappedStringTypes.cases); if (cases.size > 0) { const keys = new Set(cases.keys()); - const fullCases = enumSets.find(s => setMatches(s, keys)); - if (inference !== "none" && !isAlwaysEmptyString(Array.from(keys)) && fullCases !== undefined) { + const fullCases = enumSets.find((s) => setMatches(s, keys)); + if ( + inference !== "none" && + !isAlwaysEmptyString(Array.from(keys)) && + fullCases !== undefined + ) { types.push(builder.getEnumType(emptyTypeAttributes, fullCases)); } else { - return builder.getStringType(attributes, StringTypes.unrestricted, forwardingRef); + return builder.getStringType( + attributes, + StringTypes.unrestricted, + forwardingRef, + ); } } @@ -183,7 +218,11 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum return builder.getPrimitiveType(kind, attributes, forwardingRef); } - types.push(...Array.from(transformations).map(k => builder.getPrimitiveType(k))); + 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); } @@ -192,8 +231,8 @@ export function expandStrings(ctx: RunContext, graph: TypeGraph, inference: Enum "expand strings", stringTypeMapping, false, - allStrings.map(t => [t]), + 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 12299a07..077ba2de 100644 --- a/packages/quicktype-core/src/rewrites/FlattenStrings.ts +++ b/packages/quicktype-core/src/rewrites/FlattenStrings.ts @@ -1,13 +1,16 @@ import { iterableFirst } from "collection-utils"; import { combineTypeAttributes } from "../attributes/TypeAttributes"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; +import type { GraphRewriteBuilder } from "../GraphRewriting"; import { assert, defined } from "../support/Support"; -import { type PrimitiveType, type Type, type UnionType } from "../Type/Type"; -import { type StringTypeMapping } from "../Type/TypeBuilderUtils"; -import { type TypeGraph } from "../Type/TypeGraph"; -import { type TypeRef } from "../Type/TypeRef"; -import { combineTypeAttributesOfTypes, stringTypesForType } from "../Type/TypeUtils"; +import type { PrimitiveType, Type, UnionType } from "../Type/Type"; +import type { StringTypeMapping } from "../Type/TypeBuilderUtils"; +import type { TypeGraph } from "../Type/TypeGraph"; +import type { TypeRef } from "../Type/TypeRef"; +import { + combineTypeAttributesOfTypes, + stringTypesForType, +} from "../Type/TypeUtils"; // A union needs replacing if it contains more than one string type, one of them being // a basic string type. @@ -18,7 +21,7 @@ function unionNeedsReplacing(u: UnionType): ReadonlySet | undefined { 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; } @@ -27,12 +30,15 @@ function unionNeedsReplacing(u: UnionType): ReadonlySet | undefined { function replaceUnion( group: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { assert(group.size === 1); const u = defined(iterableFirst(group)); const stringMembers = defined(unionNeedsReplacing(u)); - const stringAttributes = combineTypeAttributesOfTypes("union", stringMembers); + const stringAttributes = combineTypeAttributesOfTypes( + "union", + stringMembers, + ); const types: TypeRef[] = []; for (const t of u.members) { if (stringMembers.has(t)) continue; @@ -43,29 +49,33 @@ function replaceUnion( 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); + return builder.getUnionType( + u.getAttributes(), + new Set(types), + forwardingRef, + ); } export function flattenStrings( graph: TypeGraph, stringTypeMapping: StringTypeMapping, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { const allUnions = graph.allNamedTypesSeparated().unions; const unionsToReplace = Array.from(allUnions) .filter(unionNeedsReplacing) - .map(t => [t]); + .map((t) => [t]); return graph.rewrite( "flatten strings", stringTypeMapping, false, unionsToReplace, debugPrintReconstitution, - replaceUnion + replaceUnion, ); } diff --git a/packages/quicktype-core/src/rewrites/FlattenUnions.ts b/packages/quicktype-core/src/rewrites/FlattenUnions.ts index fe78aa6f..73e0df28 100644 --- a/packages/quicktype-core/src/rewrites/FlattenUnions.ts +++ b/packages/quicktype-core/src/rewrites/FlattenUnions.ts @@ -1,12 +1,12 @@ import { iterableSome, setFilter } from "collection-utils"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; +import type { GraphRewriteBuilder } from "../GraphRewriting"; import { messageAssert } from "../Messages"; import { assert } from "../support/Support"; import { IntersectionType, type Type, UnionType } from "../Type/Type"; -import { type StringTypeMapping } from "../Type/TypeBuilderUtils"; -import { type TypeGraph } from "../Type/TypeGraph"; +import type { StringTypeMapping } from "../Type/TypeBuilderUtils"; +import type { TypeGraph } from "../Type/TypeGraph"; import { type TypeRef, derefTypeRef } from "../Type/TypeRef"; import { makeGroupsToFlatten } from "../Type/TypeUtils"; import { UnifyUnionBuilder, unifyTypes } from "../UnifyClasses"; @@ -16,30 +16,58 @@ export function flattenUnions( stringTypeMapping: StringTypeMapping, conflateNumbers: boolean, makeObjectTypes: boolean, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): [TypeGraph, boolean] { let needsRepeat = false; - 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]; - } + 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)); - }); - return unifyTypes(types, emptyTypeAttributes, builder, unionBuilder, conflateNumbers, forwardingRef); + needsRepeat = true; + return builder.getUnionType( + emptyTypeAttributes, + new Set(trefs), + ); + }, + ); + return unifyTypes( + types, + emptyTypeAttributes, + builder, + unionBuilder, + conflateNumbers, + forwardingRef, + ); } - const allUnions = setFilter(graph.allTypesUnordered(), t => t instanceof UnionType) as Set; - const nonCanonicalUnions = setFilter(allUnions, u => !u.isCanonical); + const allUnions = setFilter( + graph.allTypesUnordered(), + (t) => t instanceof UnionType, + ) as Set; + const nonCanonicalUnions = setFilter(allUnions, (u) => !u.isCanonical); let foundIntersection = false; - const groups = makeGroupsToFlatten(nonCanonicalUnions, members => { + const groups = makeGroupsToFlatten(nonCanonicalUnions, (members) => { messageAssert(members.size > 0, "IRNoEmptyUnions", {}); - if (!iterableSome(members, m => m instanceof IntersectionType)) return true; + if (!iterableSome(members, (m) => m instanceof IntersectionType)) + return true; // FIXME: This is stupid. `flattenUnions` returns true when no more union // flattening is necessary, but `resolveIntersections` can introduce new @@ -51,7 +79,14 @@ export function flattenUnions( foundIntersection = true; return false; }); - graph = graph.rewrite("flatten unions", stringTypeMapping, false, groups, debugPrintReconstitution, replace); + graph = graph.rewrite( + "flatten unions", + stringTypeMapping, + false, + groups, + debugPrintReconstitution, + replace, + ); // console.log(`flattened ${nonCanonicalUnions.size} of ${unions.size} unions`); return [graph, !needsRepeat && !foundIntersection]; diff --git a/packages/quicktype-core/src/rewrites/InferMaps.ts b/packages/quicktype-core/src/rewrites/InferMaps.ts index 5949a9e0..db81aefb 100644 --- a/packages/quicktype-core/src/rewrites/InferMaps.ts +++ b/packages/quicktype-core/src/rewrites/InferMaps.ts @@ -1,12 +1,18 @@ import { iterableEvery, iterableFirst, setMap } from "collection-utils"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; +import type { GraphRewriteBuilder } from "../GraphRewriting"; import { type MarkovChain, evaluate, load } from "../MarkovChain"; import { defined, panic } from "../support/Support"; -import { type ClassProperty, ClassType, type Type, isPrimitiveStringTypeKind, setOperationCasesEqual } from "../Type"; -import { type StringTypeMapping } from "../Type/TypeBuilderUtils"; -import { type TypeGraph } from "../Type/TypeGraph"; -import { type TypeRef } from "../Type/TypeRef"; +import { + type ClassProperty, + ClassType, + type Type, + isPrimitiveStringTypeKind, + setOperationCasesEqual, +} from "../Type"; +import type { StringTypeMapping } from "../Type/TypeBuilderUtils"; +import type { TypeGraph } from "../Type/TypeGraph"; +import type { TypeRef } from "../Type/TypeRef"; import { removeNullFromType } from "../Type/TypeUtils"; import { unifyTypes, unionBuilderForUnification } from "../UnifyClasses"; @@ -23,7 +29,9 @@ 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; @@ -31,15 +39,20 @@ function shouldBeMap(properties: ReadonlyMap): ReadonlySe // If all property names are digit-only, we always make a map, no // questions asked. - if (iterableEvery(properties.keys(), n => /^[0-9]+$/.test(n))) { - return setMap(properties.values(), cp => cp.type); + if (iterableEvery(properties.keys(), (n) => /^[0-9]+$/.test(n))) { + return setMap(properties.values(), (cp) => cp.type); } // If all properties are strings or null then an object must have at least // `stringMapSizeThreshold` to qualify as a map. if ( numProperties < stringMapSizeThreshold && - iterableEvery(properties.values(), cp => isPrimitiveStringTypeKind(cp.type.kind) || cp.type.kind === "null") + iterableEvery( + properties.values(), + (cp) => + isPrimitiveStringTypeKind(cp.type.kind) || + cp.type.kind === "null", + ) ) { return undefined; } @@ -64,7 +77,9 @@ function shouldBeMap(properties: ReadonlyMap): ReadonlySe // trigger-happy. const exponent = 5; const scale = Math.pow(22, exponent); - const limit = Math.pow(numProperties + 2, exponent) / scale + (0.0025 - Math.pow(3, exponent) / scale); + const limit = + Math.pow(numProperties + 2, exponent) / scale + + (0.0025 - Math.pow(3, exponent) / scale); if (probability > limit) return undefined; } @@ -88,7 +103,14 @@ function shouldBeMap(properties: ReadonlyMap): ReadonlySe if (firstNonNullCases !== undefined) { // The set of non-null cases for all other properties must // be the the same, otherwise we won't infer a map. - if (!setOperationCasesEqual(nn, firstNonNullCases, true, (a, b) => a.structurallyCompatible(b, true))) { + if ( + !setOperationCasesEqual( + nn, + firstNonNullCases, + true, + (a, b) => a.structurallyCompatible(b, true), + ) + ) { canBeMap = false; break; } @@ -111,19 +133,21 @@ export function inferMaps( graph: TypeGraph, stringTypeMapping: StringTypeMapping, conflateNumbers: boolean, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { function replaceClass( setOfOneClass: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { const c = defined(iterableFirst(setOfOneClass)); const properties = c.getProperties(); const shouldBe = shouldBeMap(properties); if (shouldBe === undefined) { - return panic(`We shouldn't be replacing class ${c.getCombinedName()} with a map`); + return panic( + `We shouldn't be replacing class ${c.getCombinedName()} with a map`, + ); } // Now reconstitute all the types in the new graph. TypeGraphs are @@ -138,14 +162,21 @@ export function inferMaps( shouldBe, c.getAttributes(), builder, - unionBuilderForUnification(builder, false, false, conflateNumbers), - conflateNumbers + unionBuilderForUnification( + builder, + false, + false, + conflateNumbers, + ), + conflateNumbers, ), - forwardingRef + forwardingRef, ); } - const classesToReplace = Array.from(graph.allNamedTypesSeparated().objects).filter(o => { + const classesToReplace = Array.from( + graph.allNamedTypesSeparated().objects, + ).filter((o) => { if (!(o instanceof ClassType)) return false; return !o.isFixed && shouldBeMap(o.getProperties()) !== undefined; }) as ClassType[]; @@ -153,8 +184,8 @@ export function inferMaps( "infer maps", stringTypeMapping, false, - classesToReplace.map(c => [c]), + 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 a4ad5c06..d1aadc06 100644 --- a/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts +++ b/packages/quicktype-core/src/rewrites/ReplaceObjectType.ts @@ -1,24 +1,24 @@ import { iterableFirst, mapMap, setFilter, setMap } from "collection-utils"; import { emptyTypeAttributes } from "../attributes/TypeAttributes"; -import { type GraphRewriteBuilder } from "../GraphRewriting"; +import type { GraphRewriteBuilder } from "../GraphRewriting"; import { defined } from "../support/Support"; -import { type ClassProperty, type ObjectType } from "../Type/Type"; -import { type StringTypeMapping } from "../Type/TypeBuilderUtils"; -import { type TypeGraph } from "../Type/TypeGraph"; -import { type TypeRef } from "../Type/TypeRef"; +import type { ClassProperty, ObjectType } from "../Type/Type"; +import type { StringTypeMapping } from "../Type/TypeBuilderUtils"; +import type { TypeGraph } from "../Type/TypeGraph"; +import type { TypeRef } from "../Type/TypeRef"; export function replaceObjectType( graph: TypeGraph, stringTypeMapping: StringTypeMapping, _conflateNumbers: boolean, leaveFullObjects: boolean, - debugPrintReconstitution: boolean + debugPrintReconstitution: boolean, ): TypeGraph { function replace( setOfOneType: ReadonlySet, builder: GraphRewriteBuilder, - forwardingRef: TypeRef + forwardingRef: TypeRef, ): TypeRef { const o = defined(iterableFirst(setOfOneType)); const attributes = o.getAttributes(); @@ -26,13 +26,21 @@ export function replaceObjectType( const additionalProperties = o.getAdditionalProperties(); function reconstituteProperties(): ReadonlyMap { - return mapMap(properties, cp => - builder.makeClassProperty(builder.reconstituteTypeRef(cp.typeRef), cp.isOptional) + return mapMap(properties, (cp) => + builder.makeClassProperty( + builder.reconstituteTypeRef(cp.typeRef), + cp.isOptional, + ), ); } function makeClass(): TypeRef { - return builder.getUniqueClassType(attributes, true, reconstituteProperties(), forwardingRef); + return builder.getUniqueClassType( + attributes, + true, + reconstituteProperties(), + forwardingRef, + ); } function reconstituteAdditionalProperties(): TypeRef { @@ -44,7 +52,11 @@ export function replaceObjectType( } if (properties.size === 0) { - return builder.getMapType(attributes, reconstituteAdditionalProperties(), forwardingRef); + return builder.getMapType( + attributes, + reconstituteAdditionalProperties(), + forwardingRef, + ); } if (additionalProperties.kind === "any") { @@ -54,11 +66,20 @@ export function replaceObjectType( } // FIXME: Warn that we're losing class semantics. - const propertyTypes = setMap(properties.values(), cp => cp.type).add(additionalProperties); - let union = builder.lookupTypeRefs(Array.from(propertyTypes).map(t => t.typeRef)); + const propertyTypes = setMap(properties.values(), (cp) => cp.type).add( + additionalProperties, + ); + let union = builder.lookupTypeRefs( + Array.from(propertyTypes).map((t) => t.typeRef), + ); if (union === undefined) { - const reconstitutedTypes = setMap(propertyTypes, t => builder.reconstituteType(t)); - union = builder.getUniqueUnionType(emptyTypeAttributes, new Set(reconstitutedTypes)); + const reconstitutedTypes = setMap(propertyTypes, (t) => + builder.reconstituteType(t), + ); + union = builder.getUniqueUnionType( + emptyTypeAttributes, + new Set(reconstitutedTypes), + ); // This is the direct unification alternative. Weirdly enough, it is a tiny // bit slower. It gives the same results. @@ -76,10 +97,25 @@ export function replaceObjectType( return builder.getMapType(attributes, union, forwardingRef); } - const allObjectTypes = setFilter(graph.allTypesUnordered(), t => t.kind === "object") as Set; + const allObjectTypes = setFilter( + graph.allTypesUnordered(), + (t) => t.kind === "object", + ) as Set; const objectTypesToReplace = leaveFullObjects - ? setFilter(allObjectTypes, o => o.getProperties().size === 0 || o.getAdditionalProperties() === undefined) + ? setFilter( + allObjectTypes, + (o) => + o.getProperties().size === 0 || + o.getAdditionalProperties() === undefined, + ) : allObjectTypes; - const groups = Array.from(objectTypesToReplace).map(t => [t]); - return graph.rewrite("replace object type", stringTypeMapping, false, groups, debugPrintReconstitution, replace); + const groups = Array.from(objectTypesToReplace).map((t) => [t]); + return graph.rewrite( + "replace object type", + stringTypeMapping, + false, + groups, + debugPrintReconstitution, + replace, + ); } diff --git a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts index 67111f9e..cf59817e 100644 --- a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts +++ b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts @@ -10,16 +10,16 @@ import { setFilter, setIntersect, setMap, - setUnionInto + setUnionInto, } from "collection-utils"; import { type TypeAttributes, combineTypeAttributes, emptyTypeAttributes, - makeTypeAttributesInferred + makeTypeAttributesInferred, } from "../attributes/TypeAttributes"; -import { type GraphRewriteBuilder, type TypeLookerUp } from "../GraphRewriting"; +import type { GraphRewriteBuilder, TypeLookerUp } from "../GraphRewriting"; import { assert, defined, mustNotHappen, panic } from "../support/Support"; import { ArrayType, @@ -31,33 +31,54 @@ import { type TypeKind, UnionType, isNumberTypeKind, - isPrimitiveTypeKind + isPrimitiveTypeKind, } from "../Type"; -import { type TypeBuilder } from "../Type/TypeBuilder"; -import { type StringTypeMapping } from "../Type/TypeBuilderUtils"; -import { type TypeGraph } from "../Type/TypeGraph"; -import { type TypeRef } from "../Type/TypeRef"; -import { makeGroupsToFlatten, matchTypeExhaustive, setOperationMembersRecursively } from "../Type/TypeUtils"; -import { type TypeAttributeMap, UnionBuilder, type UnionTypeProvider } from "../UnionBuilder"; +import type { TypeBuilder } from "../Type/TypeBuilder"; +import type { StringTypeMapping } from "../Type/TypeBuilderUtils"; +import type { TypeGraph } from "../Type/TypeGraph"; +import type { TypeRef } from "../Type/TypeRef"; +import { + makeGroupsToFlatten, + matchTypeExhaustive, + setOperationMembersRecursively, +} from "../Type/TypeUtils"; +import { + type TypeAttributeMap, + UnionBuilder, + type UnionTypeProvider, +} from "../UnionBuilder"; 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); + return iterableEvery( + members, + (m) => !(m instanceof UnionType) || m.isCanonical, + ); } -function attributesForTypes(types: ReadonlySet): TypeAttributeMap { - return mapMapEntries(types.entries(), t => [t.kind, t.getAttributes()] as [T, TypeAttributes]); +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< + ReadonlySet, + [PropertyMap, ReadonlySet | undefined] | undefined + > { private _primitiveTypes: Set | undefined; - private readonly _primitiveAttributes: TypeAttributeMap = new Map(); + private readonly _primitiveAttributes: TypeAttributeMap = + new Map(); // * undefined: We haven't seen any types yet. // * Set: All types we've seen can be arrays. @@ -83,21 +104,32 @@ class IntersectionAccumulator private _lostTypeAttributes = false; private updatePrimitiveTypes(members: Iterable): void { - const types = setFilter(members, t => isPrimitiveTypeKind(t.kind)); + const types = setFilter(members, (t) => isPrimitiveTypeKind(t.kind)); const attributes = attributesForTypes(types); - mapMergeWithInto(this._primitiveAttributes, (a, b) => combineTypeAttributes("intersect", a, b), attributes); + mapMergeWithInto( + this._primitiveAttributes, + (a, b) => combineTypeAttributes("intersect", a, b), + attributes, + ); - const kinds = setMap(types, t => t.kind) as ReadonlySet; + const kinds = setMap( + types, + (t) => t.kind, + ) as ReadonlySet; if (this._primitiveTypes === undefined) { this._primitiveTypes = new Set(kinds); return; } const haveNumber = - iterableFind(this._primitiveTypes, isNumberTypeKind) !== undefined && + iterableFind(this._primitiveTypes, isNumberTypeKind) !== + undefined && iterableFind(kinds, isNumberTypeKind) !== undefined; this._primitiveTypes = setIntersect(this._primitiveTypes, kinds); - if (haveNumber && iterableFind(this._primitiveTypes, isNumberTypeKind) === undefined) { + if ( + haveNumber && + iterableFind(this._primitiveTypes, isNumberTypeKind) === undefined + ) { // One set has integer, the other has double. The intersection // of that is integer. this._primitiveTypes = this._primitiveTypes.add("integer"); @@ -105,13 +137,20 @@ class IntersectionAccumulator } private updateArrayItemTypes(members: Iterable): void { - const maybeArray = iterableFind(members, t => t instanceof ArrayType) as ArrayType | undefined; + const maybeArray = iterableFind( + members, + (t) => t instanceof ArrayType, + ) as ArrayType | undefined; if (maybeArray === undefined) { this._arrayItemTypes = false; return; } - this._arrayAttributes = combineTypeAttributes("intersect", this._arrayAttributes, maybeArray.getAttributes()); + this._arrayAttributes = combineTypeAttributes( + "intersect", + this._arrayAttributes, + maybeArray.getAttributes(), + ); if (this._arrayItemTypes === undefined) { this._arrayItemTypes = new Set(); @@ -121,7 +160,10 @@ class IntersectionAccumulator } private updateObjectProperties(members: Iterable): void { - const maybeObject = iterableFind(members, t => t instanceof ObjectType) as ObjectType | undefined; + const maybeObject = iterableFind( + members, + (t) => t instanceof ObjectType, + ) as ObjectType | undefined; if (maybeObject === undefined) { this._objectProperties = undefined; this._additionalPropertyTypes = undefined; @@ -131,9 +173,10 @@ class IntersectionAccumulator this._objectAttributes = combineTypeAttributes( "intersect", this._objectAttributes, - maybeObject.getAttributes() + maybeObject.getAttributes(), ); - const objectAdditionalProperties = maybeObject.getAdditionalProperties(); + const objectAdditionalProperties = + maybeObject.getAdditionalProperties(); if (this._objectProperties === undefined) { assert(this._additionalPropertyTypes === undefined); @@ -142,7 +185,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); @@ -151,31 +194,48 @@ 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) { + } 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) { defined(this._objectProperties).delete(name); - } else if (newProperty !== undefined && this._additionalPropertyTypes !== undefined) { + } else if ( + newProperty !== undefined && + this._additionalPropertyTypes !== undefined + ) { // FIXME: This is potentially slow - const types = new Set(this._additionalPropertyTypes).add(newProperty.type); - defined(this._objectProperties).set(name, new GenericClassProperty(types, newProperty.isOptional)); + const types = new Set(this._additionalPropertyTypes).add( + newProperty.type, + ); + defined(this._objectProperties).set( + name, + new GenericClassProperty(types, newProperty.isOptional), + ); } else if (newProperty !== undefined) { defined(this._objectProperties).delete(name); } else { - return mustNotHappen(); + mustNotHappen(); } } - if (this._additionalPropertyTypes !== undefined && objectAdditionalProperties !== undefined) { + if ( + this._additionalPropertyTypes !== undefined && + objectAdditionalProperties !== undefined + ) { this._additionalPropertyTypes.add(objectAdditionalProperties); - } else if (this._additionalPropertyTypes !== undefined || objectAdditionalProperties !== undefined) { + } else if ( + this._additionalPropertyTypes !== undefined || + objectAdditionalProperties !== undefined + ) { this._additionalPropertyTypes = undefined; this._lostTypeAttributes = true; } @@ -191,43 +251,60 @@ class IntersectionAccumulator let attributes = t.getAttributes(); matchTypeExhaustive( t, - _noneType => { + (_noneType) => { return panic("There shouldn't be a none type"); }, - _anyType => { - return panic("The any type should have been filtered out in setOperationMembersRecursively"); + (_anyType) => { + return panic( + "The any type should have been filtered out in setOperationMembersRecursively", + ); }, - nullType => this.addUnionSet([nullType]), - boolType => this.addUnionSet([boolType]), - integerType => this.addUnionSet([integerType]), - doubleType => this.addUnionSet([doubleType]), - stringType => this.addUnionSet([stringType]), - arrayType => this.addUnionSet([arrayType]), - _classType => panic("We should never see class types in intersections"), - _mapType => panic("We should never see map types in intersections"), - objectType => this.addUnionSet([objectType]), - _enumType => panic("We should never see enum types in intersections"), - unionType => { + (nullType) => this.addUnionSet([nullType]), + (boolType) => this.addUnionSet([boolType]), + (integerType) => this.addUnionSet([integerType]), + (doubleType) => this.addUnionSet([doubleType]), + (stringType) => this.addUnionSet([stringType]), + (arrayType) => this.addUnionSet([arrayType]), + (_classType) => + panic("We should never see class types in intersections"), + (_mapType) => + panic("We should never see map types in intersections"), + (objectType) => this.addUnionSet([objectType]), + (_enumType) => + panic("We should never see enum types in intersections"), + (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); } 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"); + 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; } - public get objectData(): [PropertyMap, ReadonlySet | undefined] | undefined { + public get objectData(): + | [PropertyMap, ReadonlySet | undefined] + | undefined { if (this._objectProperties === undefined) { assert(this._additionalPropertyTypes === undefined); return undefined; @@ -241,19 +318,31 @@ class IntersectionAccumulator } public getMemberKinds(): TypeAttributeMap { - const kinds: TypeAttributeMap = mapMap(defined(this._primitiveTypes).entries(), k => - defined(this._primitiveAttributes.get(k)) + const kinds: TypeAttributeMap = mapMap( + defined(this._primitiveTypes).entries(), + (k) => defined(this._primitiveAttributes.get(k)), ); const maybeDoubleAttributes = this._primitiveAttributes.get("double"); // If double was eliminated, add its attributes to integer - if (maybeDoubleAttributes !== undefined && !kinds.has("double") && kinds.has("integer")) { + if ( + maybeDoubleAttributes !== undefined && + !kinds.has("double") && + kinds.has("integer") + ) { // FIXME: How can this ever happen??? Where do we "eliminate" double? - mapUpdateInto(kinds, "integer", a => { - return combineTypeAttributes("intersect", defined(a), maybeDoubleAttributes); + mapUpdateInto(kinds, "integer", (a) => { + return combineTypeAttributes( + "intersect", + defined(a), + maybeDoubleAttributes, + ); }); } - if (this._arrayItemTypes !== undefined && this._arrayItemTypes !== false) { + if ( + this._arrayItemTypes !== undefined && + this._arrayItemTypes !== false + ) { kinds.set("array", this._arrayAttributes); } else if (this._arrayAttributes.size > 0) { this._lostTypeAttributes = true; @@ -280,8 +369,13 @@ class IntersectionUnionBuilder extends UnionBuilder< > { private _createdNewIntersections = false; - private makeIntersection(members: ReadonlySet, attributes: TypeAttributes): TypeRef { - const reconstitutedMembers = setMap(members, t => this.typeBuilder.reconstituteTypeRef(t.typeRef)); + private makeIntersection( + members: ReadonlySet, + attributes: TypeAttributes, + ): TypeRef { + const reconstitutedMembers = setMap(members, (t) => + this.typeBuilder.reconstituteTypeRef(t.typeRef), + ); const first = defined(iterableFirst(reconstitutedMembers)); if (reconstitutedMembers.size === 1) { @@ -290,7 +384,10 @@ class IntersectionUnionBuilder extends UnionBuilder< } this._createdNewIntersections = true; - return this.typeBuilder.getUniqueIntersectionType(attributes, reconstitutedMembers); + return this.typeBuilder.getUniqueIntersectionType( + attributes, + reconstitutedMembers, + ); } public get createdNewIntersections(): boolean { @@ -300,31 +397,48 @@ class IntersectionUnionBuilder extends UnionBuilder< 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"); + return panic( + "Either properties or additional properties must be given to make an object type", + ); } const [propertyTypes, maybeAdditionalProperties] = maybeData; - const properties = mapMap(propertyTypes, cp => - this.typeBuilder.makeClassProperty(this.makeIntersection(cp.typeData, emptyTypeAttributes), cp.isOptional) + const properties = mapMap(propertyTypes, (cp) => + this.typeBuilder.makeClassProperty( + this.makeIntersection(cp.typeData, emptyTypeAttributes), + cp.isOptional, + ), ); const additionalProperties = maybeAdditionalProperties === undefined ? undefined - : this.makeIntersection(maybeAdditionalProperties, emptyTypeAttributes); - return this.typeBuilder.getUniqueObjectType(typeAttributes, properties, additionalProperties, forwardingRef); + : this.makeIntersection( + maybeAdditionalProperties, + emptyTypeAttributes, + ); + return this.typeBuilder.getUniqueObjectType( + typeAttributes, + properties, + additionalProperties, + forwardingRef, + ); } protected makeArray( arrays: ReadonlySet, typeAttributes: TypeAttributes, - forwardingRef: TypeRef | undefined + forwardingRef: TypeRef | undefined, ): TypeRef { // FIXME: attributes const itemsType = this.makeIntersection(arrays, emptyTypeAttributes); - const tref = this.typeBuilder.getArrayType(typeAttributes, itemsType, forwardingRef); + const tref = this.typeBuilder.getArrayType( + typeAttributes, + itemsType, + forwardingRef, + ); return tref; } } @@ -332,36 +446,61 @@ class IntersectionUnionBuilder extends UnionBuilder< 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 { - const intersections = setFilter(types, t => t instanceof IntersectionType) as Set; - const [members, intersectionAttributes] = setOperationMembersRecursively( - Array.from(intersections), - "intersect" - ); + 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", + ); if (members.size === 0) { - const t = builder.getPrimitiveType("any", intersectionAttributes, forwardingRef); + const t = builder.getPrimitiveType( + "any", + intersectionAttributes, + forwardingRef, + ); return t; } if (members.size === 1) { - return builder.reconstituteType(defined(iterableFirst(members)), intersectionAttributes, forwardingRef); + return builder.reconstituteType( + defined(iterableFirst(members)), + intersectionAttributes, + forwardingRef, + ); } const accumulator = new IntersectionAccumulator(); 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, ); - const attributes = combineTypeAttributes("intersect", intersectionAttributes, extraAttributes); const unionBuilder = new IntersectionUnionBuilder(builder); - const tref = unionBuilder.buildUnion(accumulator, true, attributes, forwardingRef); + const tref = unionBuilder.buildUnion( + accumulator, + true, + attributes, + forwardingRef, + ); if (unionBuilder.createdNewIntersections) { needsRepeat = true; } @@ -373,12 +512,22 @@ 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); - graph = graph.rewrite("resolve intersections", stringTypeMapping, false, groups, debugPrintReconstitution, replace); + graph = graph.rewrite( + "resolve intersections", + stringTypeMapping, + false, + groups, + debugPrintReconstitution, + replace, + ); // console.log(`resolved ${resolvableIntersections.size} of ${intersections.size} intersections`); - return [graph, !needsRepeat && allIntersections.size === resolvableIntersections.size]; + return [ + graph, + !needsRepeat && allIntersections.size === resolvableIntersections.size, + ]; } diff --git a/packages/quicktype-core/src/support/Acronyms.const.ts b/packages/quicktype-core/src/support/Acronyms.const.ts index 38523454..23154258 100644 --- a/packages/quicktype-core/src/support/Acronyms.const.ts +++ b/packages/quicktype-core/src/support/Acronyms.const.ts @@ -1,1097 +1,1097 @@ export const acronyms = [ - "aaa", - "aabb", - "aac", - "aal", - "aalc", - "aarp", - "abac", - "abcl", - "abi", - "abm", - "abr", - "ac", - "acd", - "ack", - "acl", - "acm", - "acme", - "acp", - "acpi", - "acr", - "adb", - "adc", - "adccp", - "ado", - "adsl", - "adt", - "ae", - "aes", - "af", - "afp", - "agp", - "ai", - "aix", - "alac", - "algol", - "alsa", - "alu", - "amd", - "amoled", - "amqp", - "amr", - "ann", - "ansi", - "aop", - "apci", - "api", - "apic", - "apipa", - "apl", - "apr", - "arin", - "aros", - "arp", - "arpa", - "arpanet", - "ascii", - "aset", - "asg", - "asic", - "asimo", - "aslr", - "asm", - "asmp", - "asp", - "asr", - "assp", - "ast", - "ata", - "atag", - "atapi", - "atm", - "av", - "avc", - "avi", - "awfl", - "awk", - "awt", - "bal", - "bam", - "bbp", - "bbs", - "bcd", - "bcnf", - "beep", - "ber", - "bfd", - "bfs", - "bft", - "bgp", - "bi", - "binac", - "bios", - "bjt", - "bmp", - "bnc", - "boinc", - "bom", - "bootp", - "bpdu", - "bpel", - "bpl", - "bpm", - "brm", - "brms", - "brr", - "brs", - "bsa", - "bsb", - "bsd", - "bss", - "bt", - "bw", - "byod", - "ca", - "cad", - "cae", - "cai", - "caid", - "captcha", - "caq", - "cd", - "cde", - "cdfs", - "cdma", - "cdn", - "cdp", - "cdsa", - "cert", - "ces", - "cf", - "cfd", - "cfg", - "cg", - "cga", - "cgi", - "cgt", - "chs", - "cidr", - "cifs", - "cim", - "cio", - "cir", - "cisc", - "cjk", - "cjkv", - "cli", - "clr", - "cm", - "cmdb", - "cmmi", - "cmo", - "cmos", - "cms", - "cn", - "cnc", - "cng", - "cnr", - "cobol", - "com", - "corba", - "cots", - "cpa", - "cpan", - "cpri", - "cps", - "cpu", - "cr", - "cran", - "crc", - "crlf", - "crm", - "crs", - "crt", - "crud", - "cs", - "cse", - "csi", - "csm", - "csp", - "csrf", - "css", - "csv", - "ct", - "ctan", - "ctcp", - "ctfe", - "cti", - "ctl", - "ctm", - "cts", - "ctss", - "cua", - "cvs", - "dac", - "dal", - "dao", - "dap", - "darpa", - "dat", - "db", - "dba", - "dbcs", - "dbms", - "dcc", - "dcca", - "dccp", - "dcl", - "dcmi", - "dcom", - "dcs", - "dd", - "dde", - "ddi", - "ddl", - "ddr", - "dec", - "des", - "dfa", - "dfd", - "dfs", - "dgd", - "dhcp", - "dhtml", - "dif", - "dimm", - "din", - "dip", - "dism", - "divx", - "dkim", - "dl", - "dll", - "dlna", - "dlp", - "dma", - "dmca", - "dmi", - "dml", - "dmr", - "dmz", - "dn", - "dnd", - "dns", - "doa", - "docsis", - "dom", - "dos", - "dp", - "dpc", - "dpi", - "dpmi", - "dpms", - "dr", - "dram", - "dri", - "drm", - "dsa", - "dsdl", - "dsdm", - "dsl", - "dslam", - "dsn", - "dsp", - "dsssl", - "dtd", - "dte", - "dtp", - "dtr", - "dvd", - "dvi", - "dvr", - "dw", - "eai", - "eap", - "eas", - "ebcdic", - "ebml", - "ecc", - "ecma", - "ecn", - "ecos", - "ecrs", - "eda", - "edi", - "edo", - "edsac", - "edvac", - "eeprom", - "eff", - "efi", - "efm", - "efs", - "ega", - "egp", - "eide", - "eigrp", - "eisa", - "elf", - "emacs", - "ems", - "eniac", - "eod", - "eof", - "eol", - "eom", - "eos", - "eprom", - "erd", - "erm", - "erp", - "esb", - "escon", - "esd", - "esr", - "etl", - "etw", - "euc", - "eula", - "ewmh", - "ext", - "fap", - "faq", - "fasm", - "fbdimm", - "fcb", - "fcs", - "fdc", - "fdd", - "fddi", - "fdm", - "fdma", - "fds", - "fec", - "femb", - "fet", - "fhs", - "ficon", - "fifo", - "fips", - "fl", - "flac", - "flops", - "fmc", - "fmo", - "foldoc", - "fosdem", - "fosi", - "foss", - "fp", - "fpga", - "fps", - "fpu", - "fqdn", - "fru", - "fs", - "fsb", - "fsf", - "fsm", - "ftp", - "ftta", - "fttc", - "ftth", - "fttp", - "fud", - "fvek", - "fws", - "fxp", - "fyi", - "gb", - "gcc", - "gcj", - "gcr", - "gdb", - "gdi", - "geran", - "gfdl", - "gif", - "gigo", - "gimps", - "gis", - "gml", - "gnu", - "goms", - "gpasm", - "gpfs", - "gpg", - "gpgpu", - "gpib", - "gpl", - "gprs", - "gpt", - "gpu", - "gsm", - "gui", - "guid", - "gwt", - "gyr", - "hal", - "hasp", - "hba", - "hci", - "hcl", - "hd", - "hdd", - "hdl", - "hdmi", - "hf", - "hfs", - "hhd", - "hid", - "hig", - "hird", - "hlasm", - "hls", - "hma", - "hp", - "hpc", - "hpfs", - "hsdpa", - "hsm", - "ht", - "htc", - "htm", - "html", - "http", - "https", - "htx", - "hurd", - "hvd", - "iana", - "ibm", - "ic", - "icann", - "ich", - "icmp", - "icp", - "ics", - "ict", - "id", - "ide", - "idf", - "idl", - "ids", - "iec", - "ieee", - "ietf", - "ifl", - "igmp", - "igrp", - "ihv", - "iiop", - "iis", - "ike", - "il", - "im", - "imap", - "ime", - "infosec", - "ip", - "ipam", - "ipc", - "ipl", - "ipmi", - "ipo", - "ipp", - "ips", - "iptv", - "ipx", - "ir", - "irc", - "iri", - "irp", - "irq", - "isa", - "isam", - "isatap", - "isc", - "isdn", - "iso", - "isp", - "ispf", - "isr", - "isv", - "itil", - "itl", - "itu", - "ivcr", - "ivrs", - "jaxb", - "jaxp", - "jbod", - "jce", - "jcl", - "jcp", - "jdbc", - "jdk", - "jds", - "jee", - "jes", - "jfc", - "jfet", - "jfs", - "jini", - "jit", - "jme", - "jms", - "jmx", - "jndi", - "jni", - "jnz", - "jpeg", - "jre", - "js", - "jse", - "json", - "jsp", - "jtag", - "jvm", - "kb", - "kde", - "km", - "krl", - "kvm", - "lacp", - "lan", - "lb", - "lba", - "lcd", - "lcos", - "lcr", - "ldap", - "le", - "led", - "lf", - "lfs", - "lga", - "lgpl", - "lib", - "lif", - "lifo", - "lilo", - "lisp", - "lkml", - "lm", - "loc", - "lpc", - "lpi", - "lpt", - "lru", - "lsb", - "lsi", - "lte", - "ltl", - "ltr", - "lun", - "lv", - "lvd", - "lvm", - "lzw", - "mac", - "manet", - "mapi", - "mb", - "mbcs", - "mbd", - "mbr", - "mca", - "mcad", - "mcas", - "mcdba", - "mcdst", - "mcitp", - "mcm", - "mcp", - "mcpc", - "mcpd", - "mcsa", - "mcsd", - "mcse", - "mct", - "mcts", - "mda", - "mdf", - "mdi", - "mf", - "mfc", - "mfm", - "mgcp", - "mib", - "micr", - "midi", - "mimd", - "mime", - "mimo", - "minix", - "mips", - "mis", - "misd", - "mit", - "mmc", - "mmds", - "mmf", - "mmi", - "mmio", - "mmorpg", - "mmu", - "mmx", - "mng", - "mom", - "mos", - "mosfet", - "motd", - "mous", - "mov", - "mpaa", - "mpeg", - "mpl", - "mpls", - "mpu", - "ms", - "msa", - "msb", - "msdn", - "msi", - "msn", - "mt", - "mta", - "mtbf", - "mtu", - "mua", - "mvc", - "mvp", - "mvs", - "mwc", - "mx", - "mxf", - "nack", - "nak", - "nas", - "nasm", - "ncp", - "ncq", - "ncsa", - "ndis", - "ndps", - "nds", - "nep", - "nfa", - "nfc", - "nfs", - "ngl", - "ngscb", - "ni", - "nic", - "nim", - "nio", - "nist", - "nlp", - "nls", - "nmi", - "nntp", - "noc", - "nop", - "nos", - "np", - "npl", - "nptl", - "npu", - "ns", - "nsa", - "nsi", - "nspr", - "nss", - "nt", - "ntfs", - "ntlm", - "ntp", - "numa", - "nurbs", - "nvr", - "nvram", - "oat", - "obsai", - "odbc", - "oem", - "oes", - "ofdm", - "oftc", - "oid", - "olap", - "ole", - "oled", - "olpc", - "oltp", - "omf", - "omg", - "omr", - "oo", - "ooe", - "oom", - "oop", - "ootb", - "opml", - "orb", - "orm", - "os", - "oscon", - "osdn", - "osi", - "ospf", - "oss", - "ostg", - "oui", - "pap", - "parc", - "pata", - "pbs", - "pc", - "pcb", - "pci", - "pcl", - "pcm", - "pcmcia", - "pcre", - "pd", - "pda", - "pdf", - "pdh", - "pdp", - "pe", - "perl", - "pfa", - "pg", - "pga", - "pgo", - "pgp", - "php", - "pid", - "pim", - "pio", - "pkcs", - "pki", - "plc", - "pld", - "plt", - "pmm", - "png", - "pnrp", - "poid", - "pojo", - "posix", - "ppc", - "ppi", - "ppp", - "pptp", - "pr", - "ps", - "psa", - "psm", - "psu", - "psvi", - "pv", - "pvg", - "pvr", - "pxe", - "pxi", - "qa", - "qdr", - "qfp", - "qotd", - "qsop", - "qtam", - "racf", - "rad", - "raid", - "raii", - "rait", - "ram", - "rarp", - "ras", - "rc", - "rcs", - "rd", - "rdbms", - "rdc", - "rdf", - "rdm", - "rdos", - "rdp", - "rds", - "refal", - "rest", - "rf", - "rfc", - "rfi", - "rfid", - "rgb", - "rgba", - "rhel", - "rhl", - "ria", - "riaa", - "rip", - "rir", - "risc", - "rje", - "rle", - "rll", - "rmi", - "rms", - "rom", - "romb", - "rpc", - "rpg", - "rpm", - "rras", - "rsa", - "rsi", - "rss", - "rtai", - "rtc", - "rte", - "rtems", - "rtl", - "rtos", - "rtp", - "rts", - "rtsp", - "rtti", - "rwd", - "san", - "sas", - "sata", - "sax", - "sbod", - "sbu", - "scada", - "scid", - "scm", - "scp", - "scpc", - "scpi", - "scsa", - "scsi", - "sctp", - "sd", - "sddl", - "sdh", - "sdi", - "sdio", - "sdk", - "sdl", - "sdn", - "sdp", - "sdr", - "sdram", - "sdsl", - "se", - "sec", - "sei", - "seo", - "sftp", - "sgi", - "sgml", - "sgr", - "sha", - "shdsl", - "sigcat", - "siggraph", - "simd", - "simm", - "sip", - "sisd", - "siso", - "sles", - "sli", - "slm", - "sloc", - "sma", - "smb", - "smbios", - "sme", - "smf", - "smil", - "smp", - "smps", - "sms", - "smt", - "smtp", - "sna", - "snmp", - "sntp", - "soa", - "soe", - "soho", - "soi", - "sopa", - "sp", - "spa", - "sparc", - "spf", - "spi", - "spm", - "spmd", - "sql", - "sram", - "ssa", - "ssd", - "ssdp", - "sse", - "ssh", - "ssi", - "ssid", - "ssl", - "ssp", - "ssse", - "sssp", - "sstp", - "sus", - "suse", - "svc", - "svd", - "svg", - "svga", - "swf", - "swt", - "tao", - "tapi", - "tasm", - "tb", - "tcp", - "tcu", - "tdma", - "tft", - "tftp", - "ti", - "tla", - "tld", - "tls", - "tlv", - "tnc", - "tpf", - "tpm", - "troff", - "tron", - "trsdos", - "tso", - "tsp", - "tsr", - "tta", - "ttf", - "ttl", - "tts", - "tty", - "tucows", - "twain", - "uaag", - "uac", - "uart", - "uat", - "ucs", - "uddi", - "udma", - "udp", - "uefi", - "uhf", - "ui", - "ul", - "ula", - "uma", - "umb", - "uml", - "umpc", - "umts", - "unc", - "univac", - "ups", - "uri", - "url", - "usb", - "usr", - "utc", - "utf", - "utp", - "utran", - "uucp", - "uuid", - "uun", - "uvc", - "uwp", - "ux", - "vax", - "vb", - "vba", - "vbs", - "vcpi", - "vdm", - "vdsl", - "vesa", - "vfat", - "vfs", - "vg", - "vga", - "vhf", - "vlan", - "vlb", - "vlf", - "vliw", - "vlsi", - "vlsm", - "vm", - "vmm", - "vnc", - "vod", - "vpn", - "vpu", - "vr", - "vram", - "vrml", - "vsam", - "vsat", - "vt", - "vtam", - "vtl", - "wafs", - "wai", - "wais", - "wan", - "wap", - "wasm", - "wbem", - "wcag", - "wcf", - "wdm", - "wep", - "wfi", - "wins", - "wlan", - "wma", - "wmi", - "wmv", - "wns", - "wol", - "wor", - "wora", - "wpa", - "wpad", - "wpan", - "wpf", - "wsdl", - "wsfl", - "wusb", - "wwan", - "wwdc", - "wwid", - "wwn", - "www", - "wysiwyg", - "wzc", - "xag", - "xaml", - "xcbl", - "xdm", - "xdmcp", - "xhtml", - "xilp", - "xml", - "xmms", - "xmpp", - "xms", - "xns", - "xp", - "xpcom", - "xpi", - "xpidl", - "xps", - "xsd", - "xsl", - "xslt", - "xss", - "xtf", - "xul", - "xvga", - "yaaf", - "yacc", - "yaml", - "zcav", - "zcs", - "zif", - "zifs", - "zisc", - "zma", - "zoi", - "zope", - "zpl" + "aaa", + "aabb", + "aac", + "aal", + "aalc", + "aarp", + "abac", + "abcl", + "abi", + "abm", + "abr", + "ac", + "acd", + "ack", + "acl", + "acm", + "acme", + "acp", + "acpi", + "acr", + "adb", + "adc", + "adccp", + "ado", + "adsl", + "adt", + "ae", + "aes", + "af", + "afp", + "agp", + "ai", + "aix", + "alac", + "algol", + "alsa", + "alu", + "amd", + "amoled", + "amqp", + "amr", + "ann", + "ansi", + "aop", + "apci", + "api", + "apic", + "apipa", + "apl", + "apr", + "arin", + "aros", + "arp", + "arpa", + "arpanet", + "ascii", + "aset", + "asg", + "asic", + "asimo", + "aslr", + "asm", + "asmp", + "asp", + "asr", + "assp", + "ast", + "ata", + "atag", + "atapi", + "atm", + "av", + "avc", + "avi", + "awfl", + "awk", + "awt", + "bal", + "bam", + "bbp", + "bbs", + "bcd", + "bcnf", + "beep", + "ber", + "bfd", + "bfs", + "bft", + "bgp", + "bi", + "binac", + "bios", + "bjt", + "bmp", + "bnc", + "boinc", + "bom", + "bootp", + "bpdu", + "bpel", + "bpl", + "bpm", + "brm", + "brms", + "brr", + "brs", + "bsa", + "bsb", + "bsd", + "bss", + "bt", + "bw", + "byod", + "ca", + "cad", + "cae", + "cai", + "caid", + "captcha", + "caq", + "cd", + "cde", + "cdfs", + "cdma", + "cdn", + "cdp", + "cdsa", + "cert", + "ces", + "cf", + "cfd", + "cfg", + "cg", + "cga", + "cgi", + "cgt", + "chs", + "cidr", + "cifs", + "cim", + "cio", + "cir", + "cisc", + "cjk", + "cjkv", + "cli", + "clr", + "cm", + "cmdb", + "cmmi", + "cmo", + "cmos", + "cms", + "cn", + "cnc", + "cng", + "cnr", + "cobol", + "com", + "corba", + "cots", + "cpa", + "cpan", + "cpri", + "cps", + "cpu", + "cr", + "cran", + "crc", + "crlf", + "crm", + "crs", + "crt", + "crud", + "cs", + "cse", + "csi", + "csm", + "csp", + "csrf", + "css", + "csv", + "ct", + "ctan", + "ctcp", + "ctfe", + "cti", + "ctl", + "ctm", + "cts", + "ctss", + "cua", + "cvs", + "dac", + "dal", + "dao", + "dap", + "darpa", + "dat", + "db", + "dba", + "dbcs", + "dbms", + "dcc", + "dcca", + "dccp", + "dcl", + "dcmi", + "dcom", + "dcs", + "dd", + "dde", + "ddi", + "ddl", + "ddr", + "dec", + "des", + "dfa", + "dfd", + "dfs", + "dgd", + "dhcp", + "dhtml", + "dif", + "dimm", + "din", + "dip", + "dism", + "divx", + "dkim", + "dl", + "dll", + "dlna", + "dlp", + "dma", + "dmca", + "dmi", + "dml", + "dmr", + "dmz", + "dn", + "dnd", + "dns", + "doa", + "docsis", + "dom", + "dos", + "dp", + "dpc", + "dpi", + "dpmi", + "dpms", + "dr", + "dram", + "dri", + "drm", + "dsa", + "dsdl", + "dsdm", + "dsl", + "dslam", + "dsn", + "dsp", + "dsssl", + "dtd", + "dte", + "dtp", + "dtr", + "dvd", + "dvi", + "dvr", + "dw", + "eai", + "eap", + "eas", + "ebcdic", + "ebml", + "ecc", + "ecma", + "ecn", + "ecos", + "ecrs", + "eda", + "edi", + "edo", + "edsac", + "edvac", + "eeprom", + "eff", + "efi", + "efm", + "efs", + "ega", + "egp", + "eide", + "eigrp", + "eisa", + "elf", + "emacs", + "ems", + "eniac", + "eod", + "eof", + "eol", + "eom", + "eos", + "eprom", + "erd", + "erm", + "erp", + "esb", + "escon", + "esd", + "esr", + "etl", + "etw", + "euc", + "eula", + "ewmh", + "ext", + "fap", + "faq", + "fasm", + "fbdimm", + "fcb", + "fcs", + "fdc", + "fdd", + "fddi", + "fdm", + "fdma", + "fds", + "fec", + "femb", + "fet", + "fhs", + "ficon", + "fifo", + "fips", + "fl", + "flac", + "flops", + "fmc", + "fmo", + "foldoc", + "fosdem", + "fosi", + "foss", + "fp", + "fpga", + "fps", + "fpu", + "fqdn", + "fru", + "fs", + "fsb", + "fsf", + "fsm", + "ftp", + "ftta", + "fttc", + "ftth", + "fttp", + "fud", + "fvek", + "fws", + "fxp", + "fyi", + "gb", + "gcc", + "gcj", + "gcr", + "gdb", + "gdi", + "geran", + "gfdl", + "gif", + "gigo", + "gimps", + "gis", + "gml", + "gnu", + "goms", + "gpasm", + "gpfs", + "gpg", + "gpgpu", + "gpib", + "gpl", + "gprs", + "gpt", + "gpu", + "gsm", + "gui", + "guid", + "gwt", + "gyr", + "hal", + "hasp", + "hba", + "hci", + "hcl", + "hd", + "hdd", + "hdl", + "hdmi", + "hf", + "hfs", + "hhd", + "hid", + "hig", + "hird", + "hlasm", + "hls", + "hma", + "hp", + "hpc", + "hpfs", + "hsdpa", + "hsm", + "ht", + "htc", + "htm", + "html", + "http", + "https", + "htx", + "hurd", + "hvd", + "iana", + "ibm", + "ic", + "icann", + "ich", + "icmp", + "icp", + "ics", + "ict", + "id", + "ide", + "idf", + "idl", + "ids", + "iec", + "ieee", + "ietf", + "ifl", + "igmp", + "igrp", + "ihv", + "iiop", + "iis", + "ike", + "il", + "im", + "imap", + "ime", + "infosec", + "ip", + "ipam", + "ipc", + "ipl", + "ipmi", + "ipo", + "ipp", + "ips", + "iptv", + "ipx", + "ir", + "irc", + "iri", + "irp", + "irq", + "isa", + "isam", + "isatap", + "isc", + "isdn", + "iso", + "isp", + "ispf", + "isr", + "isv", + "itil", + "itl", + "itu", + "ivcr", + "ivrs", + "jaxb", + "jaxp", + "jbod", + "jce", + "jcl", + "jcp", + "jdbc", + "jdk", + "jds", + "jee", + "jes", + "jfc", + "jfet", + "jfs", + "jini", + "jit", + "jme", + "jms", + "jmx", + "jndi", + "jni", + "jnz", + "jpeg", + "jre", + "js", + "jse", + "json", + "jsp", + "jtag", + "jvm", + "kb", + "kde", + "km", + "krl", + "kvm", + "lacp", + "lan", + "lb", + "lba", + "lcd", + "lcos", + "lcr", + "ldap", + "le", + "led", + "lf", + "lfs", + "lga", + "lgpl", + "lib", + "lif", + "lifo", + "lilo", + "lisp", + "lkml", + "lm", + "loc", + "lpc", + "lpi", + "lpt", + "lru", + "lsb", + "lsi", + "lte", + "ltl", + "ltr", + "lun", + "lv", + "lvd", + "lvm", + "lzw", + "mac", + "manet", + "mapi", + "mb", + "mbcs", + "mbd", + "mbr", + "mca", + "mcad", + "mcas", + "mcdba", + "mcdst", + "mcitp", + "mcm", + "mcp", + "mcpc", + "mcpd", + "mcsa", + "mcsd", + "mcse", + "mct", + "mcts", + "mda", + "mdf", + "mdi", + "mf", + "mfc", + "mfm", + "mgcp", + "mib", + "micr", + "midi", + "mimd", + "mime", + "mimo", + "minix", + "mips", + "mis", + "misd", + "mit", + "mmc", + "mmds", + "mmf", + "mmi", + "mmio", + "mmorpg", + "mmu", + "mmx", + "mng", + "mom", + "mos", + "mosfet", + "motd", + "mous", + "mov", + "mpaa", + "mpeg", + "mpl", + "mpls", + "mpu", + "ms", + "msa", + "msb", + "msdn", + "msi", + "msn", + "mt", + "mta", + "mtbf", + "mtu", + "mua", + "mvc", + "mvp", + "mvs", + "mwc", + "mx", + "mxf", + "nack", + "nak", + "nas", + "nasm", + "ncp", + "ncq", + "ncsa", + "ndis", + "ndps", + "nds", + "nep", + "nfa", + "nfc", + "nfs", + "ngl", + "ngscb", + "ni", + "nic", + "nim", + "nio", + "nist", + "nlp", + "nls", + "nmi", + "nntp", + "noc", + "nop", + "nos", + "np", + "npl", + "nptl", + "npu", + "ns", + "nsa", + "nsi", + "nspr", + "nss", + "nt", + "ntfs", + "ntlm", + "ntp", + "numa", + "nurbs", + "nvr", + "nvram", + "oat", + "obsai", + "odbc", + "oem", + "oes", + "ofdm", + "oftc", + "oid", + "olap", + "ole", + "oled", + "olpc", + "oltp", + "omf", + "omg", + "omr", + "oo", + "ooe", + "oom", + "oop", + "ootb", + "opml", + "orb", + "orm", + "os", + "oscon", + "osdn", + "osi", + "ospf", + "oss", + "ostg", + "oui", + "pap", + "parc", + "pata", + "pbs", + "pc", + "pcb", + "pci", + "pcl", + "pcm", + "pcmcia", + "pcre", + "pd", + "pda", + "pdf", + "pdh", + "pdp", + "pe", + "perl", + "pfa", + "pg", + "pga", + "pgo", + "pgp", + "php", + "pid", + "pim", + "pio", + "pkcs", + "pki", + "plc", + "pld", + "plt", + "pmm", + "png", + "pnrp", + "poid", + "pojo", + "posix", + "ppc", + "ppi", + "ppp", + "pptp", + "pr", + "ps", + "psa", + "psm", + "psu", + "psvi", + "pv", + "pvg", + "pvr", + "pxe", + "pxi", + "qa", + "qdr", + "qfp", + "qotd", + "qsop", + "qtam", + "racf", + "rad", + "raid", + "raii", + "rait", + "ram", + "rarp", + "ras", + "rc", + "rcs", + "rd", + "rdbms", + "rdc", + "rdf", + "rdm", + "rdos", + "rdp", + "rds", + "refal", + "rest", + "rf", + "rfc", + "rfi", + "rfid", + "rgb", + "rgba", + "rhel", + "rhl", + "ria", + "riaa", + "rip", + "rir", + "risc", + "rje", + "rle", + "rll", + "rmi", + "rms", + "rom", + "romb", + "rpc", + "rpg", + "rpm", + "rras", + "rsa", + "rsi", + "rss", + "rtai", + "rtc", + "rte", + "rtems", + "rtl", + "rtos", + "rtp", + "rts", + "rtsp", + "rtti", + "rwd", + "san", + "sas", + "sata", + "sax", + "sbod", + "sbu", + "scada", + "scid", + "scm", + "scp", + "scpc", + "scpi", + "scsa", + "scsi", + "sctp", + "sd", + "sddl", + "sdh", + "sdi", + "sdio", + "sdk", + "sdl", + "sdn", + "sdp", + "sdr", + "sdram", + "sdsl", + "se", + "sec", + "sei", + "seo", + "sftp", + "sgi", + "sgml", + "sgr", + "sha", + "shdsl", + "sigcat", + "siggraph", + "simd", + "simm", + "sip", + "sisd", + "siso", + "sles", + "sli", + "slm", + "sloc", + "sma", + "smb", + "smbios", + "sme", + "smf", + "smil", + "smp", + "smps", + "sms", + "smt", + "smtp", + "sna", + "snmp", + "sntp", + "soa", + "soe", + "soho", + "soi", + "sopa", + "sp", + "spa", + "sparc", + "spf", + "spi", + "spm", + "spmd", + "sql", + "sram", + "ssa", + "ssd", + "ssdp", + "sse", + "ssh", + "ssi", + "ssid", + "ssl", + "ssp", + "ssse", + "sssp", + "sstp", + "sus", + "suse", + "svc", + "svd", + "svg", + "svga", + "swf", + "swt", + "tao", + "tapi", + "tasm", + "tb", + "tcp", + "tcu", + "tdma", + "tft", + "tftp", + "ti", + "tla", + "tld", + "tls", + "tlv", + "tnc", + "tpf", + "tpm", + "troff", + "tron", + "trsdos", + "tso", + "tsp", + "tsr", + "tta", + "ttf", + "ttl", + "tts", + "tty", + "tucows", + "twain", + "uaag", + "uac", + "uart", + "uat", + "ucs", + "uddi", + "udma", + "udp", + "uefi", + "uhf", + "ui", + "ul", + "ula", + "uma", + "umb", + "uml", + "umpc", + "umts", + "unc", + "univac", + "ups", + "uri", + "url", + "usb", + "usr", + "utc", + "utf", + "utp", + "utran", + "uucp", + "uuid", + "uun", + "uvc", + "uwp", + "ux", + "vax", + "vb", + "vba", + "vbs", + "vcpi", + "vdm", + "vdsl", + "vesa", + "vfat", + "vfs", + "vg", + "vga", + "vhf", + "vlan", + "vlb", + "vlf", + "vliw", + "vlsi", + "vlsm", + "vm", + "vmm", + "vnc", + "vod", + "vpn", + "vpu", + "vr", + "vram", + "vrml", + "vsam", + "vsat", + "vt", + "vtam", + "vtl", + "wafs", + "wai", + "wais", + "wan", + "wap", + "wasm", + "wbem", + "wcag", + "wcf", + "wdm", + "wep", + "wfi", + "wins", + "wlan", + "wma", + "wmi", + "wmv", + "wns", + "wol", + "wor", + "wora", + "wpa", + "wpad", + "wpan", + "wpf", + "wsdl", + "wsfl", + "wusb", + "wwan", + "wwdc", + "wwid", + "wwn", + "www", + "wysiwyg", + "wzc", + "xag", + "xaml", + "xcbl", + "xdm", + "xdmcp", + "xhtml", + "xilp", + "xml", + "xmms", + "xmpp", + "xms", + "xns", + "xp", + "xpcom", + "xpi", + "xpidl", + "xps", + "xsd", + "xsl", + "xslt", + "xss", + "xtf", + "xul", + "xvga", + "yaaf", + "yacc", + "yaml", + "zcav", + "zcs", + "zif", + "zifs", + "zisc", + "zma", + "zoi", + "zope", + "zpl", ] as const; diff --git a/packages/quicktype-core/src/support/Acronyms.ts b/packages/quicktype-core/src/support/Acronyms.ts index a5c71540..7c6ca043 100644 --- a/packages/quicktype-core/src/support/Acronyms.ts +++ b/packages/quicktype-core/src/support/Acronyms.ts @@ -1,38 +1,41 @@ import { EnumOption } from "../RendererOptions"; -import { allLowerWordStyle, allUpperWordStyle, firstUpperWordStyle, originalWord } from "./Strings"; +import { + allLowerWordStyle, + allUpperWordStyle, + firstUpperWordStyle, + originalWord, +} from "./Strings"; export enum AcronymStyleOptions { Camel = "camel", Lower = "lowerCase", Original = "original", - Pascal = "pascal" + Pascal = "pascal", } -export const acronymOption = function (defaultOption: AcronymStyleOptions) { - return new EnumOption( +export const acronymOption = (defaultOption: AcronymStyleOptions) => new EnumOption( "acronym-style", "Acronym naming style", { [AcronymStyleOptions.Original]: AcronymStyleOptions.Original, [AcronymStyleOptions.Pascal]: AcronymStyleOptions.Pascal, [AcronymStyleOptions.Camel]: AcronymStyleOptions.Camel, - [AcronymStyleOptions.Lower]: AcronymStyleOptions.Lower + [AcronymStyleOptions.Lower]: AcronymStyleOptions.Lower, } as const, defaultOption, - "secondary" + "secondary", ); -}; const options = { [AcronymStyleOptions.Pascal]: allUpperWordStyle, [AcronymStyleOptions.Camel]: firstUpperWordStyle, [AcronymStyleOptions.Original]: originalWord, - [AcronymStyleOptions.Lower]: allLowerWordStyle + [AcronymStyleOptions.Lower]: allLowerWordStyle, } as const; export function acronymStyle( - style: AcronymStyle + style: AcronymStyle, ): (typeof options)[AcronymStyle] { return options[style]; } diff --git a/packages/quicktype-core/src/support/Chance.ts b/packages/quicktype-core/src/support/Chance.ts index 74f8162a..f4c553c5 100644 --- a/packages/quicktype-core/src/support/Chance.ts +++ b/packages/quicktype-core/src/support/Chance.ts @@ -74,7 +74,9 @@ class MersenneTwister { for (this.mti = 1; this.mti < this.N; this.mti++) { 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[]. */ @@ -87,7 +89,7 @@ class MersenneTwister { /* generates a random number on [0,0xffffffff]-interval */ private genrand_int32() { let y; - let mag01 = [0x0, this.MATRIX_A]; + const mag01 = [0x0, this.MATRIX_A]; /* mag01[x] = x * MATRIX_A for x=0,1 */ if (this.mti >= this.N) { @@ -100,17 +102,27 @@ 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); + 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; } @@ -158,7 +170,9 @@ export class Chance { * @throws {RangeError} min cannot be greater than max */ integer(options: { max: number; min: number }): number { - return Math.floor(this.random() * (options.max - options.min + 1) + options.min); + return Math.floor( + this.random() * (options.max - options.min + 1) + options.min, + ); } /** @@ -186,7 +200,15 @@ export class Chance { 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"]; + const animalTypeArray = [ + "desert", + "forest", + "ocean", + "zoo", + "farm", + "pet", + "grassland", + ]; return this.pick(animals[this.pick(animalTypeArray)]); } @@ -490,7 +512,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: [ @@ -583,7 +605,7 @@ const animals: { [kind: string]: string[] } = { "Vulture", "Waxwing", "Xerus", - "Zebra" + "Zebra", ], grassland: [ "Aardvark", @@ -726,7 +748,7 @@ const animals: { [kind: string]: string[] } = { "Thornbill", "Thrush", "Toad", - "Tortoise" + "Tortoise", ], forest: [ "Agouti", @@ -922,7 +944,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: [ @@ -953,7 +975,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: [ @@ -999,7 +1021,7 @@ const animals: { [kind: string]: string[] } = { "Sugar Gliders", "Tarantula", "Turkeys", - "Turtles" + "Turtles", ], // list of zoo animals comes from https://bronxzoo.com/animals zoo: [ @@ -1069,8 +1091,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 @@ -2171,5 +2193,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 38dd9641..5437fbd0 100644 --- a/packages/quicktype-core/src/support/Comments.ts +++ b/packages/quicktype-core/src/support/Comments.ts @@ -1,4 +1,4 @@ -import { type Sourcelike } from "../Source"; +import type { Sourcelike } from "../Source"; export interface CommentOptions { afterComment?: string; @@ -18,7 +18,10 @@ type CustomCommentConfig = CommentOptions & { customLines: Sourcelike[]; }; -export type CommentConfig = DescriptionBlockCommentConfig | InlineCommentConfig | CustomCommentConfig; +export type CommentConfig = + | DescriptionBlockCommentConfig + | InlineCommentConfig + | CustomCommentConfig; export type Comment = string | CommentConfig; diff --git a/packages/quicktype-core/src/support/Converters.ts b/packages/quicktype-core/src/support/Converters.ts index 0bc2f58f..282e4e54 100644 --- a/packages/quicktype-core/src/support/Converters.ts +++ b/packages/quicktype-core/src/support/Converters.ts @@ -2,7 +2,7 @@ import { EnumOption } from "../RendererOptions"; export enum ConvertersOptions { AllObjects = "all-objects", - TopLevel = "top-level" + TopLevel = "top-level", } export function convertersOption() { @@ -11,9 +11,9 @@ export function convertersOption() { "Which converters to generate (top-level by default)", { [ConvertersOptions.TopLevel]: ConvertersOptions.TopLevel, - [ConvertersOptions.AllObjects]: ConvertersOptions.AllObjects + [ConvertersOptions.AllObjects]: ConvertersOptions.AllObjects, } as const, ConvertersOptions.TopLevel, - "secondary" + "secondary", ); } diff --git a/packages/quicktype-core/src/support/Strings.ts b/packages/quicktype-core/src/support/Strings.ts index 1b0614ad..0c4fd217 100644 --- a/packages/quicktype-core/src/support/Strings.ts +++ b/packages/quicktype-core/src/support/Strings.ts @@ -36,19 +36,21 @@ 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); - }; + return (cp: number) => 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); // eslint-disable-next-line @typescript-eslint/naming-convention @@ -91,7 +93,9 @@ 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); // eslint-disable-next-line @typescript-eslint/naming-convention @@ -109,7 +113,11 @@ export function utf32ConcatMap(mapper: (codePoint: number) => string): (s: strin const highSurrogate = cc; i++; const lowSurrogate = s.charCodeAt(i); - messageAssert(isLowSurrogate(lowSurrogate), "MiscUnicodeHighSurrogateWithoutLowSurrogate", {}); + messageAssert( + isLowSurrogate(lowSurrogate), + "MiscUnicodeHighSurrogateWithoutLowSurrogate", + {}, + ); const highBits = highSurrogate - 0xd800; const lowBits = lowSurrogate - 0xdc00; cc = 0x10000 + lowBits + (highBits << 10); @@ -136,12 +144,18 @@ 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 { @@ -167,7 +181,7 @@ export function repeatString(s: string, n: number): string { } export function intToHex(i: number, width: number): string { - let str = i.toString(16); + const str = i.toString(16); if (str.length >= width) return str; return repeatString("0", width - str.length) + str; } @@ -182,7 +196,7 @@ export function standardUnicodeHexEscape(codePoint: number): string { export function escapeNonPrintableMapper( printablePredicate: (codePoint: number) => boolean, - escaper: (codePoint: number) => string + escaper: (codePoint: number) => string, ): (u: number) => string { function mapper(u: number): string { switch (u) { @@ -206,8 +220,12 @@ export function escapeNonPrintableMapper( return mapper; } -export const utf16StringEscape = utf16ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape)); -export const stringEscape = utf32ConcatMap(escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape)); +export const utf16StringEscape = utf16ConcatMap( + escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape), +); +export const stringEscape = utf32ConcatMap( + escapeNonPrintableMapper(isPrintable, standardUnicodeHexEscape), +); export function isPrintable(codePoint: number): boolean { if (codePoint > 0xffff) return false; @@ -235,7 +253,7 @@ export function isPrintable(codePoint: number): boolean { "Pi", "Nl", "Mn", - "Lo" + "Lo", ].includes(category); } @@ -293,11 +311,11 @@ function modifyFirstChar(f: (c: string) => string, s: string): string { } export function capitalize(str: string): string { - return modifyFirstChar(c => c.toUpperCase(), str); + return modifyFirstChar((c) => c.toUpperCase(), str); } export function decapitalize(str: string): string { - return modifyFirstChar(c => c.toLowerCase(), str); + return modifyFirstChar((c) => c.toLowerCase(), str); } const wordSeparatorRegex = /[-_. ]+/; @@ -319,7 +337,7 @@ export function snakeCase(str: string): string { 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"); @@ -335,10 +353,18 @@ export interface WordInName { } const fastIsWordCharacter = precomputedCodePointPredicate(isWordCharacter); -const fastIsNonWordCharacter = precomputedCodePointPredicate(cp => !isWordCharacter(cp)); -const fastIsLowerCase = precomputedCodePointPredicate(cp => unicode.isLowerCase(cp)); -export const fastIsUpperCase = precomputedCodePointPredicate(cp => unicode.isUpperCase(cp)); -const fastNonLetter = precomputedCodePointPredicate(cp => !unicode.isLowerCase(cp) && !unicode.isUpperCase(cp)); +const fastIsNonWordCharacter = precomputedCodePointPredicate( + (cp) => !isWordCharacter(cp), +); +const fastIsLowerCase = precomputedCodePointPredicate((cp) => + unicode.isLowerCase(cp), +); +export const fastIsUpperCase = precomputedCodePointPredicate((cp) => + unicode.isUpperCase(cp), +); +const fastNonLetter = precomputedCodePointPredicate( + (cp) => !unicode.isLowerCase(cp) && !unicode.isUpperCase(cp), +); const fastIsDigit = precomputedCodePointPredicate(isDigit); export function splitIntoWords(s: string): WordInName[] { @@ -387,7 +413,10 @@ export function splitIntoWords(s: string): WordInName[] { } function startInterval(): void { - assert(intervalStart === undefined, "Interval started before last one was committed"); + assert( + intervalStart === undefined, + "Interval started before last one was committed", + ); intervalStart = i; } @@ -406,7 +435,9 @@ export function splitIntoWords(s: string): WordInName[] { i += 1; } - const allUpper = lastLowerCaseIndex === undefined || lastLowerCaseIndex < intervalStart; + const allUpper = + lastLowerCaseIndex === undefined || + lastLowerCaseIndex < intervalStart; intervals.push([intervalStart, i, allUpper]); intervalStart = undefined; } @@ -498,7 +529,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) { @@ -509,7 +540,10 @@ 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 }); } @@ -520,11 +554,14 @@ 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; @@ -549,7 +586,7 @@ export function addPrefixIfNecessary(prefix: string, name: string): string { export function makeNameStyle( namingStyle: NamingStyle, legalizeName: (name: string) => string, - prefix?: string + prefix?: string, ): (rawName: string) => string { let separator: string; let firstWordStyle: WordStyle; @@ -564,7 +601,10 @@ export function makeNameStyle( namingStyle === "camel-upper-acronyms" ) { separator = ""; - if (namingStyle === "pascal-upper-acronyms" || namingStyle === "camel-upper-acronyms") { + if ( + namingStyle === "pascal-upper-acronyms" || + namingStyle === "camel-upper-acronyms" + ) { restWordStyle = firstUpperWordStyle; restAcronymStyle = allUpperWordStyle; } else { @@ -584,10 +624,18 @@ export function makeNameStyle( firstWordStyle = firstWordAcronymStyle = allLowerWordStyle; break; case "underscore": - firstWordStyle = restWordStyle = firstWordAcronymStyle = restAcronymStyle = allLowerWordStyle; + firstWordStyle = + restWordStyle = + firstWordAcronymStyle = + restAcronymStyle = + allLowerWordStyle; break; case "upper-underscore": - firstWordStyle = restWordStyle = firstWordAcronymStyle = restAcronymStyle = allUpperWordStyle; + firstWordStyle = + restWordStyle = + firstWordAcronymStyle = + restAcronymStyle = + allUpperWordStyle; break; default: return assertNever(namingStyle); @@ -604,7 +652,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 3715a710..d81fa26f 100644 --- a/packages/quicktype-core/src/support/Support.ts +++ b/packages/quicktype-core/src/support/Support.ts @@ -2,17 +2,22 @@ import { Base64 } from "js-base64"; import * as pako from "pako"; import * as YAML from "yaml"; -import { type JSONSchema } from "../input/JSONSchemaStore"; +import type { JSONSchema } from "../input/JSONSchemaStore"; import { messageError } from "../Messages"; export interface StringMap { - // eslint-disable-next-line @typescript-eslint/no-explicit-any [name: string]: any; } 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 { +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; } @@ -34,8 +39,14 @@ export function checkString(x: unknown): x is string { } 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 { +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; } @@ -48,8 +59,14 @@ export function checkStringMap(x: unknown, checkValue?: (v: unknown) => v is } 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[] { +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}`); } @@ -124,7 +141,11 @@ export function inflateBase64(encoded: string): string { return pako.inflate(bytes, { to: "string" }); } -export function parseJSON(text: string, description: string, address = ""): JSONSchema | undefined { +export function parseJSON( + text: string, + description: string, + address = "", +): JSONSchema | undefined { try { // https://gist.github.com/pbakondy/f5045eff725193dad9c7 if (text.charCodeAt(0) === 0xfeff) { @@ -141,7 +162,11 @@ export function parseJSON(text: string, description: string, address = "): number[] { +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 index 22a702b5..e692e2b8 100644 --- a/packages/quicktype-core/src/types.ts +++ b/packages/quicktype-core/src/types.ts @@ -1,9 +1,2 @@ export * from "./language/types"; export * from "./language/options.types"; - -// FIXME: remove these when options are strongly typed -/* eslint-disable @typescript-eslint/no-explicit-any */ -export type FixMeOptionsType = Record; - -// FIXME: Remove this post TS5.4 -export type NoInfer = [T][T extends any ? 0 : never]; diff --git a/packages/quicktype-graphql-input/package.json b/packages/quicktype-graphql-input/package.json index 8a17ead1..24432249 100644 --- a/packages/quicktype-graphql-input/package.json +++ b/packages/quicktype-graphql-input/package.json @@ -18,9 +18,7 @@ "devDependencies": { "@types/node": "18.19.31", "@types/graphql": "^0.11.7", - "typescript": "4.9.5" + "typescript": "~5.8.3" }, - "files": [ - "dist" - ] + "files": ["dist"] } diff --git a/packages/quicktype-graphql-input/src/GraphQLSchema.ts b/packages/quicktype-graphql-input/src/GraphQLSchema.ts index e53072ba..77e762f7 100644 --- a/packages/quicktype-graphql-input/src/GraphQLSchema.ts +++ b/packages/quicktype-graphql-input/src/GraphQLSchema.ts @@ -20,7 +20,7 @@ export enum __DirectiveLocation { ENUM = "ENUM", // Location adjacent to an enum definition. ENUM_VALUE = "ENUM_VALUE", // Location adjacent to an enum value definition. INPUT_OBJECT = "INPUT_OBJECT", // Location adjacent to an input object type definition. - INPUT_FIELD_DEFINITION = "INPUT_FIELD_DEFINITION" // Location adjacent to an input object field definition. + INPUT_FIELD_DEFINITION = "INPUT_FIELD_DEFINITION", // Location adjacent to an input object field definition. } // An enum describing what kind of type a given `__Type` is. @@ -32,7 +32,7 @@ export enum TypeKind { ENUM = "ENUM", // Indicates this type is an enum. `enumValues` is a valid field. INPUT_OBJECT = "INPUT_OBJECT", // Indicates this type is an input object. `inputFields` is a valid field. LIST = "LIST", // Indicates this type is a list. `ofType` is a valid field. - NON_NULL = "NON_NULL" // Indicates this type is a non-null. `ofType` is a valid field. + NON_NULL = "NON_NULL", // Indicates this type is a non-null. `ofType` is a valid field. } export type GraphQLSchema = { diff --git a/packages/quicktype-graphql-input/src/index.ts b/packages/quicktype-graphql-input/src/index.ts index 1b18754a..7bce8160 100644 --- a/packages/quicktype-graphql-input/src/index.ts +++ b/packages/quicktype-graphql-input/src/index.ts @@ -1,13 +1,13 @@ import { iterableFirst, mapFromObject, setMap } from "collection-utils"; import * as graphql from "graphql/language"; -import { - type DirectiveNode, - type DocumentNode, - type FieldNode, - type FragmentDefinitionNode, - type OperationDefinitionNode, - type SelectionNode, - type SelectionSetNode +import type { + DirectiveNode, + DocumentNode, + FieldNode, + FragmentDefinitionNode, + OperationDefinitionNode, + SelectionNode, + SelectionSetNode, } from "graphql/language/ast"; import { type ClassProperty, @@ -26,7 +26,7 @@ import { messageAssert, namesTypeAttributeKind, panic, - removeNullFromUnion + removeNullFromUnion, } from "quicktype-core"; import { type GraphQLSchema, TypeKind } from "./GraphQLSchema"; @@ -63,7 +63,10 @@ interface InputValue { } function getField(t: GQLType, name: string): Field { - if (!t.fields) return panic(`Required field ${name} in type ${t.name} which doesn't have fields.`); + if (!t.fields) + return panic( + `Required field ${name} in type ${t.name} which doesn't have fields.`, + ); for (const f of t.fields) { if (f.name === name) { return f; @@ -73,12 +76,19 @@ function getField(t: GQLType, name: string): Field { return panic(`Required field ${name} not defined on type ${t.name}.`); } -function makeNames(name: string, fieldName: string | null, containingTypeName: string | null): TypeAttributes { +function makeNames( + name: string, + fieldName: string | null, + containingTypeName: string | null, +): TypeAttributes { const alternatives: string[] = []; if (fieldName) alternatives.push(fieldName); if (containingTypeName) alternatives.push(`${containingTypeName}_${name}`); - if (fieldName && containingTypeName) alternatives.push(`${containingTypeName}_${fieldName}`); - return namesTypeAttributeKind.makeAttributes(TypeNames.make(new Set([name]), new Set(alternatives), false)); + if (fieldName && containingTypeName) + alternatives.push(`${containingTypeName}_${fieldName}`); + return namesTypeAttributeKind.makeAttributes( + TypeNames.make(new Set([name]), new Set(alternatives), false), + ); } function makeNullable( @@ -86,17 +96,25 @@ function makeNullable( tref: TypeRef, name: string, fieldName: string | null, - containingTypeName: string + containingTypeName: string, ): TypeRef { const typeNames = makeNames(name, fieldName, containingTypeName); const t = derefTypeRef(tref, builder.typeGraph); if (!(t instanceof UnionType)) { - return builder.getUnionType(typeNames, new Set([tref, builder.getPrimitiveType("null")])); + return builder.getUnionType( + typeNames, + new Set([tref, builder.getPrimitiveType("null")]), + ); } const [maybeNull, nonNulls] = removeNullFromUnion(t); if (maybeNull) return tref; - return builder.getUnionType(typeNames, setMap(nonNulls, nn => nn.typeRef).add(builder.getPrimitiveType("null"))); + return builder.getUnionType( + typeNames, + setMap(nonNulls, (nn) => nn.typeRef).add( + builder.getPrimitiveType("null"), + ), + ); } // This is really not the way to do this, but it's easy and works. By default @@ -117,7 +135,7 @@ function removeNull(builder: TypeBuilder, tref: TypeRef): TypeRef { if (nonNulls.size === 1) return first.typeRef; return builder.getUnionType( t.getAttributes(), - setMap(nonNulls, nn => nn.typeRef) + setMap(nonNulls, (nn) => nn.typeRef), ); } @@ -134,7 +152,10 @@ function makeScalar(builder: TypeBuilder, ft: GQLType): TypeRef { return builder.getPrimitiveType("double"); default: // FIXME: support ID specifically? - return builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted); + return builder.getStringType( + emptyTypeAttributes, + StringTypes.unrestricted, + ); } } @@ -154,10 +175,18 @@ 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) })); + .map((s) => ({ + selection: s, + inType, + optional: optional || hasOptionalDirectives(s.directives), + })); } interface GQLSchema { @@ -197,7 +226,7 @@ class GQLQuery { builder: TypeBuilder, fieldNode: FieldNode, fieldType: GQLType, - containingTypeName: string + containingTypeName: string, ): TypeRef => { let optional = hasOptionalDirectives(fieldNode.directives); let result: TypeRef; @@ -220,18 +249,18 @@ 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); + const values = fieldType.enumValues.map((ev) => ev.name); let name: string; let fieldName: string | null; if (fieldType.name) { @@ -243,7 +272,10 @@ class GQLQuery { } optional = true; - result = builder.getEnumType(makeNames(name, fieldName, containingTypeName), new Set(values)); + result = builder.getEnumType( + makeNames(name, fieldName, containingTypeName), + new Set(values), + ); break; case TypeKind.INPUT_OBJECT: // FIXME: Support input objects @@ -256,7 +288,12 @@ 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: @@ -266,7 +303,12 @@ class GQLQuery { result = removeNull( builder, - this.makeIRTypeFromFieldNode(builder, fieldNode, fieldType.ofType, containingTypeName) + this.makeIRTypeFromFieldNode( + builder, + fieldNode, + fieldType.ofType, + containingTypeName, + ), ); break; default: @@ -274,7 +316,13 @@ class GQLQuery { } if (optional) { - result = makeNullable(builder, result, fieldNode.name.value, null, containingTypeName); + result = makeNullable( + builder, + result, + fieldNode.name.value, + null, + containingTypeName, + ); } return result; @@ -292,18 +340,22 @@ class GQLQuery { gqlType: GQLType, containingFieldName: string | null, containingTypeName: string | null, - overrideName?: string + overrideName?: string, ): TypeRef => { if ( gqlType.kind !== TypeKind.OBJECT && gqlType.kind !== TypeKind.INTERFACE && gqlType.kind !== TypeKind.UNION ) { - return panic("Type for selection set is not object, interface, or union."); + 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."); + return panic( + "Object, interface, or union type doesn't have a name.", + ); } const nameOrOverride = overrideName ?? gqlType.name; @@ -316,16 +368,32 @@ class GQLQuery { switch (selection.kind) { case "Field": const fieldName = selection.name.value; - const givenName = selection.alias ? selection.alias.value : fieldName; + const givenName = selection.alias + ? selection.alias.value + : fieldName; const field = getField(inType, fieldName); - let fieldType = this.makeIRTypeFromFieldNode(builder, selection, field.type, nameOrOverride); - properties.set(givenName, builder.makeClassProperty(fieldType, optional)); + const fieldType = this.makeIRTypeFromFieldNode( + builder, + selection, + field.type, + nameOrOverride, + ); + properties.set( + givenName, + builder.makeClassProperty(fieldType, optional), + ); break; case "FragmentSpread": { const fragment = this.getFragment(selection.name.value); - const fragmentType = this._schema.types[fragment.typeCondition.name.value]; - const fragmentOptional = optional || fragmentType.name !== inType.name; - const expanded = expandSelectionSet(fragment.selectionSet, fragmentType, fragmentOptional); + const fragmentType = + this._schema.types[fragment.typeCondition.name.value]; + const fragmentOptional = + optional || fragmentType.name !== inType.name; + const expanded = expandSelectionSet( + fragment.selectionSet, + fragmentType, + fragmentOptional, + ); selections = selections.concat(expanded); break; } @@ -336,8 +404,14 @@ class GQLQuery { ? this._schema.types[selection.typeCondition.name.value] : inType; const fragmentOptional = - optional || fragmentType.name !== inType.name || hasOptionalDirectives(selection.directives); - const expanded = expandSelectionSet(selection.selectionSet, fragmentType, fragmentOptional); + optional || + fragmentType.name !== inType.name || + hasOptionalDirectives(selection.directives); + const expanded = expandSelectionSet( + selection.selectionSet, + fragmentType, + fragmentOptional, + ); selections = selections.concat(expanded); break; } @@ -347,10 +421,17 @@ class GQLQuery { } } - return builder.getClassType(makeNames(nameOrOverride, containingFieldName, containingTypeName), properties); + return builder.getClassType( + makeNames(nameOrOverride, containingFieldName, containingTypeName), + properties, + ); }; - public 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, @@ -358,7 +439,7 @@ class GQLQuery { this._schema.queryType, null, queryName, - "data" + "data", ); } @@ -373,7 +454,7 @@ class GQLQuery { this._schema.mutationType, null, queryName, - "data" + "data", ); } @@ -398,7 +479,11 @@ class GQLSchemaFromJSON implements GQLSchema { for (const t of schema.__schema.types as GQLType[]) { if (!t.name) return panic("No top-level type name given"); - this.types[t.name] = { kind: t.kind, name: t.name, description: t.description }; + this.types[t.name] = { + kind: t.kind, + name: t.name, + description: t.description, + }; } for (const t of schema.__schema.types) { @@ -432,14 +517,17 @@ class GQLSchemaFromJSON implements GQLSchema { this.mutationType = mutationType; } - private readonly addTypeFields = (target: GQLType, source: GQLType): void => { + private readonly addTypeFields = ( + target: GQLType, + source: GQLType, + ): void => { if (source.fields) { - target.fields = source.fields.map(f => { + 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`); @@ -461,7 +549,7 @@ class GQLSchemaFromJSON implements GQLSchema { } if (source.enumValues) { - target.enumValues = source.enumValues.map(ev => { + target.enumValues = source.enumValues.map((ev) => { return { name: ev.name, description: ev.description }; }); // console.log(`${target.name} has ${target.enumValues.length} enumValues`); @@ -473,7 +561,7 @@ class GQLSchemaFromJSON implements GQLSchema { name: iv.name, description: iv.description, type: this.makeType(iv.type), - defaultValue: iv.defaultValue + defaultValue: iv.defaultValue, }; }; @@ -484,11 +572,12 @@ class GQLSchemaFromJSON implements GQLSchema { return namedType; } - if (!t.ofType) return panic(`Type of kind ${t.kind} has neither name nor ofType`); + 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; @@ -499,7 +588,7 @@ function makeGraphQLQueryTypes( topLevelName: string, builder: TypeBuilder, json: { data: GraphQLSchema }, - queryString: string + queryString: string, ): Map { const schema = new GQLSchemaFromJSON(json); const query = new GQLQuery(schema, queryString); @@ -513,29 +602,42 @@ 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)), + namesTypeAttributeKind.makeAttributes( + TypeNames.make( + new Set(["error"]), + new Set(["graphQLError"]), + false, + ), + ), mapFromObject({ message: builder.makeClassProperty( - builder.getStringType(emptyTypeAttributes, StringTypes.unrestricted), - false - ) - }) + builder.getStringType( + emptyTypeAttributes, + StringTypes.unrestricted, + ), + 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); } @@ -572,7 +674,7 @@ export class GraphQLInput implements Input { public addSourceSync(source: GraphQLSourceData): void { this._topLevels.set(source.name, { schema: source.schema, - query: source.query + query: source.query, }); } @@ -580,15 +682,26 @@ export class GraphQLInput implements Input { return undefined; } - public async addTypes(ctx: RunContext, typeBuilder: TypeBuilder): Promise { + public async addTypes( + ctx: RunContext, + typeBuilder: TypeBuilder, + ): Promise { this.addTypesSync(ctx, typeBuilder); } public addTypesSync(_ctx: RunContext, typeBuilder: TypeBuilder): void { for (const [name, { schema, query }] of this._topLevels) { - const newTopLevels = makeGraphQLQueryTypes(name, typeBuilder, schema, query); + const newTopLevels = makeGraphQLQueryTypes( + name, + typeBuilder, + schema, + query, + ); for (const [actualName, t] of newTopLevels) { - typeBuilder.addTopLevel(this._topLevels.size === 1 ? name : actualName, t); + typeBuilder.addTopLevel( + this._topLevels.size === 1 ? name : actualName, + t, + ); } } } diff --git a/packages/quicktype-typescript-input/package.json b/packages/quicktype-typescript-input/package.json index b624fd08..773c5417 100644 --- a/packages/quicktype-typescript-input/package.json +++ b/packages/quicktype-typescript-input/package.json @@ -18,7 +18,5 @@ "devDependencies": { "@types/node": "18.19.31" }, - "files": [ - "dist" - ] + "files": ["dist"] } diff --git a/packages/quicktype-typescript-input/src/index.ts b/packages/quicktype-typescript-input/src/index.ts index 3289e914..6cf0cc42 100644 --- a/packages/quicktype-typescript-input/src/index.ts +++ b/packages/quicktype-typescript-input/src/index.ts @@ -1,12 +1,19 @@ -import { type PartialArgs, generateSchema } from "@mark.probst/typescript-json-schema"; -import { type JSONSchemaSourceData, defined, messageError } from "quicktype-core"; +import { + type PartialArgs, + generateSchema, +} from "@mark.probst/typescript-json-schema"; +import { + type JSONSchemaSourceData, + defined, + messageError, +} from "quicktype-core"; import * as ts from "typescript"; const settings: PartialArgs = { required: true, titles: true, topRef: true, - noExtraProps: true + noExtraProps: true, }; const compilerOptions: ts.CompilerOptions = { @@ -17,21 +24,26 @@ 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 +// 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); + 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"), }); } + // this breaks after upgrading to TS 5+ const schema = generateSchema(program, "*", settings); const uris: string[] = []; let topLevelName = ""; @@ -39,8 +51,12 @@ export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchem // 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" + const matchingDefaultName = Object.entries( + schema?.definitions ?? {}, + ).find( + ([_name, definition]) => + (definition as Record).$ref === + "#/definitions/default", )?.[0]; if (matchingDefaultName) { @@ -48,11 +64,17 @@ export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchem (defaultDefinition as Record).title = topLevelName; schema.definitions[matchingDefaultName] = defaultDefinition; - schema.definitions.default = { $ref: `#/definitions/${matchingDefaultName}` }; + schema.definitions.default = { + $ref: `#/definitions/${matchingDefaultName}`, + }; } } - if (schema !== null && typeof schema === "object" && typeof schema.definitions === "object") { + if ( + schema !== null && + typeof schema === "object" && + typeof schema.definitions === "object" + ) { for (const name of Object.getOwnPropertyNames(schema.definitions)) { const definition = schema.definitions[name]; if ( @@ -71,7 +93,9 @@ export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchem } const index = defined(matches.index); - definition.description = description.slice(0, index) + description.slice(index + matches[0].length); + definition.description = + description.slice(0, index) + + description.slice(index + matches[0].length); uris.push(`#/definitions/${name}`); @@ -89,5 +113,10 @@ export function schemaForTypeScriptSources(sourceFileNames: string[]): JSONSchem uris.push("#/definitions/"); } - return { schema: JSON.stringify(schema), name: topLevelName, uris, isConverted: true }; + return { + schema: JSON.stringify(schema), + name: topLevelName, + uris, + isConverted: true, + }; } diff --git a/packages/quicktype-vscode/package.json b/packages/quicktype-vscode/package.json index 5c96e9b5..a30f0783 100644 --- a/packages/quicktype-vscode/package.json +++ b/packages/quicktype-vscode/package.json @@ -24,13 +24,8 @@ "engines": { "vscode": "^1.87.0" }, - "categories": [ - "Other" - ], - "keywords": [ - "json", - "converter" - ], + "categories": ["Other"], + "keywords": ["json", "converter"], "markdown": "github", "main": "dist/extension.js", "vsce": { @@ -154,7 +149,7 @@ "@vscode/test-electron": "^2.3.9", "@vscode/vsce": "^2.25.0", "eslint": "^8.56.0", - "typescript": "^5.3.3", + "typescript": "~5.8.3", "node-persist": "^4.0.1", "quicktype-core": "file:../quicktype-core", "quicktype-typescript-input": "file:../quicktype-typescript-input", diff --git a/packages/quicktype-vscode/src/extension.ts b/packages/quicktype-vscode/src/extension.ts index fecc619a..cba2a301 100644 --- a/packages/quicktype-vscode/src/extension.ts +++ b/packages/quicktype-vscode/src/extension.ts @@ -1,4 +1,4 @@ -"use strict"; + import * as path from "path"; @@ -14,7 +14,7 @@ import { isLanguageName, jsonInputForTargetLanguage, languageNamed, - quicktype + quicktype, } from "quicktype-core"; import { schemaForTypeScriptSources } from "quicktype-typescript-input"; // eslint-disable-next-line import/no-unresolved @@ -31,7 +31,7 @@ enum Command { OpenQuicktypeForJSON = "quicktype.openForJSON", OpenQuicktypeForJSONSchema = "quicktype.openForJSONSchema", OpenQuicktypeForTypeScript = "quicktype.openForTypeScript", - ChangeTargetLanguage = "quicktype.changeTargetLanguage" + ChangeTargetLanguage = "quicktype.changeTargetLanguage", } function jsonIsValid(json: string): boolean { @@ -44,15 +44,18 @@ function jsonIsValid(json: string): boolean { return true; } -async function promptTopLevelName(): Promise<{ cancelled: boolean; name: string }> { - let topLevelName = await vscode.window.showInputBox({ - prompt: "Top-level type name?" +async function promptTopLevelName(): Promise<{ + cancelled: boolean; + name: string; +}> { + const topLevelName = await vscode.window.showInputBox({ + prompt: "Top-level type name?", }); return { cancelled: topLevelName === undefined, // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - name: topLevelName || "TopLevel" + name: topLevelName || "TopLevel", }; } @@ -62,8 +65,10 @@ interface TargetLanguagePick { } async function pickTargetLanguage(): Promise { - const languageChoices = defaultTargetLanguages.map(l => l.displayName).sort(); - let chosenName = await vscode.window.showQuickPick(languageChoices); + const languageChoices = defaultTargetLanguages + .map((l) => l.displayName) + .sort(); + const chosenName = await vscode.window.showQuickPick(languageChoices); const cancelled = chosenName === undefined; if (chosenName === undefined || !isLanguageName(chosenName)) { return { cancelled, lang: languageNamed("typescript") }; @@ -72,14 +77,18 @@ async function pickTargetLanguage(): Promise { return { cancelled, lang: languageNamed(chosenName) }; } -async function getTargetLanguage(editor: vscode.TextEditor): Promise { +async function getTargetLanguage( + editor: vscode.TextEditor, +): Promise { const documentLanguage = editor.document.languageId; - const languageName = isLanguageName(documentLanguage) ? documentLanguage : "typescript"; + const languageName = isLanguageName(documentLanguage) + ? documentLanguage + : "typescript"; const currentLanguage = languageNamed(languageName); if (currentLanguage !== undefined) { return { cancelled: false, - lang: currentLanguage + lang: currentLanguage, }; } @@ -94,18 +103,21 @@ async function runQuicktype( lang: TargetLanguage, topLevelName: string, forceJustTypes: boolean, - indentation: string | undefined + indentation: string | undefined, ): Promise { - const configuration = vscode.workspace.getConfiguration(configurationSection); + const configuration = + vscode.workspace.getConfiguration(configurationSection); const justTypes = forceJustTypes || configuration.justTypes; const rendererOptions: RendererOptions = {}; if (justTypes) { // FIXME: The target language should have a property to return these options. if (lang.name === "csharp") { - (rendererOptions as RendererOptions<"csharp">).features = "just-types"; + (rendererOptions as RendererOptions<"csharp">).features = + "just-types"; } else if (lang.name === "kotlin") { - (rendererOptions as RendererOptions<"kotlin">).framework = "just-types"; + (rendererOptions as RendererOptions<"kotlin">).framework = + "just-types"; } else if ("just-types" in rendererOptions) { rendererOptions["just-types"] = "true"; } @@ -114,22 +126,24 @@ async function runQuicktype( const inputData = new InputData(); switch (kind) { case "json": - await inputData.addSource("json", { name: topLevelName, samples: [content] }, () => - jsonInputForTargetLanguage(lang) + await inputData.addSource( + "json", + { name: topLevelName, samples: [content] }, + () => jsonInputForTargetLanguage(lang), ); break; case "schema": await inputData.addSource( "schema", { name: topLevelName, schema: content }, - () => new JSONSchemaInput(undefined) + () => new JSONSchemaInput(undefined), ); break; case "typescript": await inputData.addSource( "schema", schemaForTypeScriptSources([`${topLevelName}.ts`]), - () => new JSONSchemaInput(undefined) + () => new JSONSchemaInput(undefined), ); break; default: @@ -144,7 +158,7 @@ async function runQuicktype( inferMaps: configuration.inferMaps, inferEnums: configuration.inferEnums, inferDateTimes: configuration.inferDateTimes, - inferIntegerStrings: configuration.inferIntegerStrings + inferIntegerStrings: configuration.inferIntegerStrings, }; for (const flag of inferenceFlagNames) { if (typeof configuration[flag] === "boolean") { @@ -155,7 +169,11 @@ async function runQuicktype( return await quicktype(options); } -async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justTypes: boolean): Promise { +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; @@ -173,11 +191,15 @@ async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justType try { content = await vscode.env.clipboard.readText(); } catch (e) { - return await vscode.window.showErrorMessage("Could not get clipboard contents"); + return await vscode.window.showErrorMessage( + "Could not get clipboard contents", + ); } if (kind !== "typescript" && !jsonIsValid(content)) { - return await vscode.window.showErrorMessage("Clipboard does not contain valid JSON."); + return await vscode.window.showErrorMessage( + "Clipboard does not contain valid JSON.", + ); } let topLevelName: string; @@ -194,7 +216,14 @@ async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justType let result: SerializedRenderResult; try { - result = await runQuicktype(content, kind, language.lang, topLevelName, justTypes, indentation); + result = await runQuicktype( + content, + kind, + language.lang, + topLevelName, + justTypes, + indentation, + ); } catch (e) { // TODO Invalid JSON produces an uncatchable exception from quicktype // Fix this so we can catch and show an error message. @@ -206,11 +235,14 @@ async function pasteAsTypes(editor: vscode.TextEditor, kind: InputKind, justType // @ts-expect-error const text = result.lines.join("\n"); const selection = editor.selection; - return await editor.edit(builder => { + return await editor.edit((builder) => { if (selection.isEmpty) { builder.insert(selection.start, text); } else { - builder.replace(new vscode.Range(selection.start, selection.end), text); + builder.replace( + new vscode.Range(selection.start, selection.end), + text, + ); } }); } @@ -220,7 +252,7 @@ class CodeProvider implements vscode.TextDocumentContentProvider { public readonly uri: vscode.Uri; - private _documentText: string = "{}"; + private _documentText = "{}"; private _targetCode = ""; @@ -239,19 +271,25 @@ class CodeProvider implements vscode.TextDocumentContentProvider { public constructor( private _inputKind: InputKind, private readonly _targetLanguage: TargetLanguage, - private _document: vscode.TextDocument + private _document: vscode.TextDocument, ) { this.scheme = `quicktype-${this._targetLanguage.name}`; // TODO use this.documentName instead of QuickType in uri - this.uri = vscode.Uri.parse(`${this.scheme}:QuickType.${this._targetLanguage.extension}`); + this.uri = vscode.Uri.parse( + `${this.scheme}:QuickType.${this._targetLanguage.extension}`, + ); - this._changeSubscription = vscode.workspace.onDidChangeTextDocument(ev => this.textDidChange(ev)); - this._onDidChangeVisibleTextEditors = vscode.window.onDidChangeVisibleTextEditors(editors => - this.visibleTextEditorsDidChange([...editors]) - ); - this._onDidChangeConfiguration = vscode.workspace.onDidChangeConfiguration(ev => - this.configurationDidChange(ev) + this._changeSubscription = vscode.workspace.onDidChangeTextDocument( + (ev) => this.textDidChange(ev), ); + this._onDidChangeVisibleTextEditors = + vscode.window.onDidChangeVisibleTextEditors((editors) => + this.visibleTextEditorsDidChange([...editors]), + ); + this._onDidChangeConfiguration = + vscode.workspace.onDidChangeConfiguration((ev) => + this.configurationDidChange(ev), + ); } public dispose(): void { @@ -288,7 +326,9 @@ class CodeProvider implements vscode.TextDocumentContentProvider { } private visibleTextEditorsDidChange(editors: vscode.TextEditor[]): void { - const isOpen = editors.some(e => e.document.uri.scheme === this.scheme); + const isOpen = editors.some( + (e) => e.document.uri.scheme === this.scheme, + ); if (!this._isOpen && isOpen) { void this.update(); } @@ -327,7 +367,7 @@ class CodeProvider implements vscode.TextDocumentContentProvider { this._targetLanguage, this.documentName, false, - undefined + undefined, ); this._targetCode = result.lines.join("\n"); @@ -341,7 +381,7 @@ class CodeProvider implements vscode.TextDocumentContentProvider { public provideTextDocumentContent( _uri: vscode.Uri, - _token: vscode.CancellationToken + _token: vscode.CancellationToken, ): vscode.ProviderResult { this._isOpen = true; @@ -385,7 +425,7 @@ let explicitlySetTargetLanguage: TargetLanguage | undefined = undefined; async function openQuicktype( inputKind: InputKind, targetLanguage: TargetLanguage, - document: vscode.TextDocument + document: vscode.TextDocument, ): Promise { let codeProvider = codeProviders.get(targetLanguage.name); if (codeProvider === undefined) { @@ -393,7 +433,10 @@ async function openQuicktype( codeProviders.set(targetLanguage.name, codeProvider); if (extensionContext !== undefined) { extensionContext.subscriptions.push( - vscode.workspace.registerTextDocumentContentProvider(codeProvider.scheme, codeProvider) + vscode.workspace.registerTextDocumentContentProvider( + codeProvider.scheme, + codeProvider, + ), ); } } else { @@ -404,7 +447,9 @@ async function openQuicktype( let originalEditor: vscode.TextEditor | undefined; if (lastCodeProvider !== undefined) { const lastDoc = lastCodeProvider.document; - originalEditor = vscode.window.visibleTextEditors.find(e => e.document === lastDoc); + originalEditor = vscode.window.visibleTextEditors.find( + (e) => e.document === lastDoc, + ); } if (originalEditor === undefined) { @@ -425,8 +470,12 @@ async function openQuicktype( return await vscode.window.showTextDocument(doc, column, true); } -async function openForEditor(editor: vscode.TextEditor, inputKind: InputKind): Promise { - const targetLanguage = explicitlySetTargetLanguage ?? deduceTargetLanguage(); +async function openForEditor( + editor: vscode.TextEditor, + inputKind: InputKind, +): Promise { + const targetLanguage = + explicitlySetTargetLanguage ?? deduceTargetLanguage(); await openQuicktype(inputKind, targetLanguage, editor.document); } @@ -437,51 +486,65 @@ async function changeTargetLanguage(): Promise { explicitlySetTargetLanguage = pick.lang; if (lastCodeProvider === undefined) return; - await openQuicktype(lastCodeProvider.inputKind, explicitlySetTargetLanguage, lastCodeProvider.document); + await openQuicktype( + lastCodeProvider.inputKind, + explicitlySetTargetLanguage, + lastCodeProvider.document, + ); - await extensionContext?.workspaceState.update(lastTargetLanguageUsedKey, explicitlySetTargetLanguage.name); + await extensionContext?.workspaceState.update( + lastTargetLanguageUsedKey, + explicitlySetTargetLanguage.name, + ); } -export async function activate(context: vscode.ExtensionContext): Promise { +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) + async (editor) => await pasteAsTypes(editor, "json", true), ), vscode.commands.registerTextEditorCommand( Command.PasteJSONAsTypesAndSerialization, - async editor => await pasteAsTypes(editor, "json", false) + async (editor) => await pasteAsTypes(editor, "json", false), ), vscode.commands.registerTextEditorCommand( Command.PasteSchemaAsTypes, - async editor => await pasteAsTypes(editor, "schema", true) + async (editor) => await pasteAsTypes(editor, "schema", true), ), vscode.commands.registerTextEditorCommand( Command.PasteSchemaAsTypesAndSerialization, - async editor => await pasteAsTypes(editor, "schema", false) + async (editor) => await pasteAsTypes(editor, "schema", false), ), vscode.commands.registerTextEditorCommand( Command.PasteTypeScriptAsTypesAndSerialization, - async editor => await pasteAsTypes(editor, "typescript", false) + async (editor) => await pasteAsTypes(editor, "typescript", false), ), vscode.commands.registerTextEditorCommand( Command.OpenQuicktypeForJSON, - async editor => await openForEditor(editor, "json") + async (editor) => await openForEditor(editor, "json"), ), vscode.commands.registerTextEditorCommand( Command.OpenQuicktypeForJSONSchema, - async editor => await openForEditor(editor, "schema") + async (editor) => await openForEditor(editor, "schema"), ), vscode.commands.registerTextEditorCommand( Command.OpenQuicktypeForTypeScript, - async editor => await openForEditor(editor, "typescript") + async (editor) => await openForEditor(editor, "typescript"), + ), + vscode.commands.registerCommand( + Command.ChangeTargetLanguage, + changeTargetLanguage, ), - vscode.commands.registerCommand(Command.ChangeTargetLanguage, changeTargetLanguage) ); - const maybeName = extensionContext.workspaceState.get(lastTargetLanguageUsedKey); + const maybeName = extensionContext.workspaceState.get( + lastTargetLanguageUsedKey, + ); if (typeof maybeName === "string" && isLanguageName(maybeName)) { explicitlySetTargetLanguage = languageNamed(maybeName); } diff --git a/packages/quicktype-vscode/tsconfig.json b/packages/quicktype-vscode/tsconfig.json index 2e4d0e4e..53cccc39 100644 --- a/packages/quicktype-vscode/tsconfig.json +++ b/packages/quicktype-vscode/tsconfig.json @@ -3,10 +3,7 @@ "module": "commonjs", "target": "es6", "outDir": "out", - "lib": [ - "es6", - "esnext.asynciterable" - ], + "lib": ["es6", "esnext.asynciterable"], "sourceMap": true, "rootDir": ".", "allowJs": false, @@ -15,8 +12,5 @@ "noUnusedParameters": true, "esModuleInterop": true }, - "exclude": [ - "node_modules", - ".vscode-test" - ] -} \ No newline at end of file + "exclude": ["node_modules", ".vscode-test"] +} diff --git a/script/patch-npm-version.ts b/script/patch-npm-version.ts index 67caf403..2cc64461 100755 --- a/script/patch-npm-version.ts +++ b/script/patch-npm-version.ts @@ -21,12 +21,16 @@ const PUBLISHED = (() => { const CURRENT = exec(`npm version`).match(/quicktype: '(.+)'/)![1]; switch (semver.compare(CURRENT, PUBLISHED)) { case -1: - console.error(`* package.json version is ${CURRENT} but ${PUBLISHED} is published. Patching...`); + console.error( + `* package.json version is ${CURRENT} but ${PUBLISHED} is published. Patching...`, + ); exec(`npm version ${PUBLISHED} --force --no-git-tag-version`); shell.exec(`npm version patch --no-git-tag-version`); break; case 0: - console.error(`* package.json version is ${CURRENT} but ${PUBLISHED} is published. Patching...`); + console.error( + `* package.json version is ${CURRENT} but ${PUBLISHED} is published. Patching...`, + ); shell.exec(`npm version patch --no-git-tag-version`); break; default: diff --git a/script/publish.sh b/script/publish.sh index 2960be7e..e82da152 100755 --- a/script/publish.sh +++ b/script/publish.sh @@ -30,7 +30,7 @@ mv package.1.json package.json npm publish popd -# pubish quicktype +# Publish quicktype jq --arg version $VERSION \ '.dependencies."quicktype-core" = $version | .dependencies."quicktype-graphql-input" = $version | .dependencies."quicktype-typescript-input" = $version' \ package.json > package.1.json @@ -41,4 +41,4 @@ npm publish # Publish vscode extension pushd packages/quicktype-vscode npm run pub -popd \ No newline at end of file +popd diff --git a/src/CompressedJSONFromStream.ts b/src/CompressedJSONFromStream.ts index 16a9c78b..892e3592 100644 --- a/src/CompressedJSONFromStream.ts +++ b/src/CompressedJSONFromStream.ts @@ -1,4 +1,4 @@ -import { type Readable } from "readable-stream"; +import type { Readable } from "readable-stream"; import { Parser } from "stream-json"; import { CompressedJSON, type Value } from "quicktype-core"; @@ -15,18 +15,21 @@ const methodMap: { [name: string]: string } = { stringValue: "commitString", nullValue: "commitNull", trueValue: "handleTrueValue", - falseValue: "handleFalseValue" + falseValue: "handleFalseValue", }; export class CompressedJSONFromStream extends CompressedJSON { public async parse(readStream: Readable): Promise { const combo = new Parser({ packKeys: true, packStrings: true }); - combo.on("data", (item: { name: string; value: string | undefined }) => { - if (typeof methodMap[item.name] === "string") { - // @ts-expect-error FIXME: strongly type this - this[methodMap[item.name]](item.value); - } - }); + combo.on( + "data", + (item: { name: string; value: string | undefined }) => { + if (typeof methodMap[item.name] === "string") { + // @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()); diff --git a/src/GraphQLIntrospection.ts b/src/GraphQLIntrospection.ts index 840cf3c5..db2093a0 100644 --- a/src/GraphQLIntrospection.ts +++ b/src/GraphQLIntrospection.ts @@ -7,12 +7,16 @@ import { panic } from "quicktype-core"; // https://github.com/apollographql/apollo-codegen/blob/master/src/downloadSchema.ts 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 { +export async function introspectServer( + url: string, + method: string, + headerStrings: string[], +): Promise { const headers: { [name: string]: string } = {}; for (const name of Object.getOwnPropertyNames(defaultHeaders)) { @@ -33,21 +37,27 @@ 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(); } catch (error) { - return panic(`Error while fetching introspection query result: ${exceptionToString(error)}`); + return panic( + `Error while fetching introspection query result: ${exceptionToString(error)}`, + ); } if (result.errors) { - return panic(`Errors in introspection query result: ${JSON.stringify(result.errors)}`); + return panic( + `Errors in introspection query result: ${JSON.stringify(result.errors)}`, + ); } const schemaData = result; if (!schemaData.data) { - return panic(`No introspection query result data found, server responded with: ${JSON.stringify(result)}`); + return panic( + `No introspection query result data found, server responded with: ${JSON.stringify(result)}`, + ); } return JSON.stringify(schemaData, null, 2); diff --git a/src/TypeSource.ts b/src/TypeSource.ts index 1c58e2e7..ee6b2203 100644 --- a/src/TypeSource.ts +++ b/src/TypeSource.ts @@ -1,7 +1,7 @@ -import { type Readable } from "readable-stream"; +import type { Readable } from "readable-stream"; -import { type JSONSchemaSourceData, type JSONSourceData } from "quicktype-core"; -import { type GraphQLSourceData } from "quicktype-graphql-input"; +import type { JSONSchemaSourceData, JSONSourceData } 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 3eaaaa1c..b8977899 100644 --- a/src/URLGrammar.ts +++ b/src/URLGrammar.ts @@ -37,7 +37,9 @@ function expand(json: unknown): string[] { return panic(`Value is not a valid URL grammar: ${json}`); } -export function urlsFromURLGrammar(json: unknown): { [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 82099eef..550e90d4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,15 +1,21 @@ #!/usr/bin/env node -import * as fs from "fs"; -import * as path from "path"; +import * as fs from "node:fs"; +import * as path from "node: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 { + definedMap, + // biome-ignore lint/suspicious/noShadowRestrictedNames: + 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 type { Readable } from "readable-stream"; import stringToStream from "string-to-stream"; import _wordwrap from "wordwrap"; @@ -46,14 +52,19 @@ import { readableFromFileOrURL, sourcesFromPostmanCollection, splitIntoWords, - trainMarkovChain + trainMarkovChain, } from "quicktype-core"; import { GraphQLInput } from "quicktype-graphql-input"; import { schemaForTypeScriptSources } from "quicktype-typescript-input"; import { CompressedJSONFromStream } from "./CompressedJSONFromStream"; import { introspectServer } from "./GraphQLIntrospection"; -import { type GraphQLTypeSource, type JSONTypeSource, type SchemaTypeSource, type TypeSource } from "./TypeSource"; +import type { + GraphQLTypeSource, + JSONTypeSource, + SchemaTypeSource, + TypeSource, +} from "./TypeSource"; import { urlsFromURLGrammar } from "./URLGrammar"; // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires @@ -63,7 +74,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 + // biome-ignore lint/suspicious/noExplicitAny: [option: string]: any; additionalSchema: string[]; allPropertiesOptional: boolean; @@ -97,9 +108,13 @@ const defaultDefaultTargetLanguageName = "go"; 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))); + const samples = await Promise.all( + filesOrUrls.map( + async (file) => await readableFromFileOrURL(file, httpHeaders), + ), + ); return { kind: "json", name, samples }; } @@ -108,12 +123,17 @@ function typeNameFromFilename(filename: string): string { 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)) - .filter(x => fs.lstatSync(x).isFile()); + .map((x) => path.join(d, x)) + .filter((x) => fs.lstatSync(x).isFile()); // Each file is a (Name, JSON | URL) const sourcesInDir: TypeSource[] = []; const graphQLSources: GraphQLTypeSource[] = []; @@ -134,36 +154,53 @@ 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 - }); - graphQLSchema = await readableFromFileOrURL(fileOrUrl, httpHeaders); + messageAssert( + graphQLSchema === undefined, + "DriverMoreThanOneGraphQLSchemaInDir", + { + dir: dataDir, + }, + ); + graphQLSchema = await readableFromFileOrURL( + fileOrUrl, + httpHeaders, + ); graphQLSchemaFileName = fileOrUrl; } else if (file.endsWith(".graphql")) { graphQLSources.push({ kind: "graphql", name, schema: undefined, - query: await getStream(await readableFromFileOrURL(fileOrUrl, httpHeaders)) + query: await getStream( + await readableFromFileOrURL(fileOrUrl, httpHeaders), + ), }); } } if (graphQLSources.length > 0) { if (graphQLSchema === undefined) { - return messageError("DriverNoGraphQLSchemaInDir", { dir: dataDir }); + return messageError("DriverNoGraphQLSchemaInDir", { + dir: dataDir, + }); } - const schema = parseJSON(await getStream(graphQLSchema), "GraphQL schema", graphQLSchemaFileName); + const schema = parseJSON( + await getStream(graphQLSchema), + "GraphQL schema", + graphQLSchemaFileName, + ); for (const source of graphQLSources) { source.schema = schema; sourcesInDir.push(source); @@ -173,8 +210,8 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr return sourcesInDir; } - const contents = fs.readdirSync(dataDir).map(x => path.join(dataDir, x)); - const directories = contents.filter(x => fs.lstatSync(x).isDirectory()); + const contents = fs.readdirSync(dataDir).map((x) => path.join(dataDir, x)); + const directories = contents.filter((x) => fs.lstatSync(x).isDirectory()); let sources = await readFilesOrURLsInDirectory(dataDir); @@ -199,13 +236,22 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr } } - if (jsonSamples.length > 0 && schemaSources.length + graphQLSources.length > 0) { - return messageError("DriverCannotMixJSONWithOtherSamples", { dir: dir }); + if ( + jsonSamples.length > 0 && + schemaSources.length + graphQLSources.length > 0 + ) { + return messageError("DriverCannotMixJSONWithOtherSamples", { + dir: dir, + }); } // FIXME: rewrite this to be clearer - const oneUnlessEmpty = (xs: TypeSource[]): 0 | 1 => Math.sign(xs.length) as 0 | 1; - if (oneUnlessEmpty(schemaSources) + oneUnlessEmpty(graphQLSources) > 1) { + const oneUnlessEmpty = (xs: TypeSource[]): 0 | 1 => + Math.sign(xs.length) as 0 | 1; + if ( + oneUnlessEmpty(schemaSources) + oneUnlessEmpty(graphQLSources) > + 1 + ) { return messageError("DriverCannotMixNonJSONInputs", { dir: dir }); } @@ -213,7 +259,7 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr sources.push({ kind: "json", name: path.basename(dir), - samples: jsonSamples + samples: jsonSamples, }); } @@ -224,10 +270,13 @@ async function samplesFromDirectory(dataDir: string, httpHeaders?: string[]): Pr return sources; } -function inferLang(options: Partial, defaultLanguage: LanguageName): string | LanguageName { +function inferLang( + options: Partial, + defaultLanguage: LanguageName, +): string | LanguageName { // Output file extension determines the language if language is undefined if (options.out !== undefined) { - let extension = path.extname(options.out); + const extension = path.extname(options.out); if (extension === "") { return messageError("DriverNoLanguageOrExtension", {}); } @@ -241,28 +290,42 @@ function inferLang(options: Partial, defaultLanguage: LanguageName): function inferTopLevel(options: Partial): string { // Output file name determines the top-level if undefined if (options.out !== undefined) { - let extension = path.extname(options.out); - let without = path.basename(options.out).replace(extension, ""); + const extension = path.extname(options.out); + const without = path.basename(options.out).replace(extension, ""); return without; } // Source determines the top-level if undefined if (options.src !== undefined && options.src.length === 1) { - let src = options.src[0]; - let extension = path.extname(src); - let without = path.basename(src).replace(extension, ""); + const src = options.src[0]; + const extension = path.extname(src); + const without = path.basename(src).replace(extension, ""); return without; } 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", {}); + if ( + opts.graphqlSchema !== undefined || + opts.graphqlIntrospect !== undefined + ) { + messageAssert( + srcLang === undefined || srcLang === "graphql", + "DriverSourceLangMustBeGraphQL", + {}, + ); srcLang = "graphql"; - } else if (opts.src !== undefined && opts.src.length > 0 && opts.src.every(file => _.endsWith(file, ".ts"))) { + } else if ( + opts.src !== undefined && + opts.src.length > 0 && + opts.src.every((file) => _.endsWith(file, ".ts")) + ) { srcLang = "typescript"; } else { messageAssert(srcLang !== "graphql", "DriverGraphQLSchemaNeeded", {}); @@ -273,12 +336,15 @@ function inferCLIOptions(opts: Partial, targetLanguage: TargetLangua if (targetLanguage !== undefined) { language = targetLanguage; } else { - const languageName = opts.lang ?? inferLang(opts, defaultDefaultTargetLanguageName); + const languageName = + opts.lang ?? inferLang(opts, defaultDefaultTargetLanguageName); if (isLanguageName(languageName)) { language = languageNamed(languageName); } else { - return messageError("DriverUnknownOutputLanguage", { lang: languageName }); + return messageError("DriverUnknownOutputLanguage", { + lang: languageName, + }); } } @@ -303,7 +369,7 @@ 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); @@ -314,8 +380,13 @@ function inferCLIOptions(opts: Partial, targetLanguage: TargetLangua } function makeLangTypeLabel(targetLanguages: readonly TargetLanguage[]): string { - assert(targetLanguages.length > 0, "Must have at least one target language"); - return targetLanguages.map(r => _.minBy(r.names, s => s.length)).join("|"); + 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 { @@ -329,11 +400,13 @@ function negatedInferenceFlagName(name: string): string { function dashedFromCamelCase(name: string): string { return splitIntoWords(name) - .map(w => w.word.toLowerCase()) + .map((w) => w.word.toLowerCase()) .join("-"); } -function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): OptionDefinition[] { +function makeOptionDefinitions( + targetLanguages: readonly TargetLanguage[], +): OptionDefinition[] { const beforeLang: OptionDefinition[] = [ { name: "out", @@ -341,7 +414,7 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti type: String, typeLabel: "FILE", description: "The output file. Determines --lang and --top-level.", - kind: "cli" + kind: "cli", }, { name: "top-level", @@ -349,8 +422,8 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti type: String, typeLabel: "NAME", description: "The name for the top level type.", - kind: "cli" - } + kind: "cli", + }, ]; const lang: OptionDefinition[] = targetLanguages.length < 2 @@ -362,8 +435,8 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti type: String, typeLabel: "LANG", description: "The target language.", - kind: "cli" - } + kind: "cli", + }, ]; const afterLang: OptionDefinition[] = [ { @@ -373,7 +446,7 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti defaultValue: undefined, typeLabel: "SRC_LANG", description: "The source language (default is json).", - kind: "cli" + kind: "cli", }, { name: "src", @@ -382,15 +455,15 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti defaultOption: true, typeLabel: "FILE|URL|DIRECTORY", description: "The file, url, or data directory to type.", - kind: "cli" + kind: "cli", }, { name: "src-urls", type: String, typeLabel: "FILE", description: "Tracery grammar describing URLs to crawl.", - kind: "cli" - } + kind: "cli", + }, ]; const inference: OptionDefinition[] = Array.from( mapMap(mapFromObject(inferenceFlags), (flag, name) => { @@ -398,9 +471,9 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti name: dashedFromCamelCase(negatedInferenceFlagName(name)), type: Boolean, description: flag.negationDescription + ".", - kind: "cli" as const + kind: "cli" as const, }; - }).values() + }).values(), ); const afterInference: OptionDefinition[] = [ { @@ -408,29 +481,31 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti type: String, typeLabel: "FILE", description: "GraphQL introspection file.", - kind: "cli" + kind: "cli", }, { name: "graphql-introspect", type: String, typeLabel: "URL", description: "Introspect GraphQL schema from a server.", - kind: "cli" + kind: "cli", }, { name: "http-method", type: String, typeLabel: "METHOD", - description: "HTTP method to use for the GraphQL introspection query.", - kind: "cli" + description: + "HTTP method to use for the GraphQL introspection query.", + kind: "cli", }, { name: "http-header", type: String, multiple: true, typeLabel: "HEADER", - description: "Header(s) to attach to all HTTP requests, including the GraphQL introspection query.", - kind: "cli" + description: + "Header(s) to attach to all HTTP requests, including the GraphQL introspection query.", + kind: "cli", }, { name: "additional-schema", @@ -439,38 +514,38 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti multiple: true, typeLabel: "FILE", description: "Register the $id's of additional JSON Schema files.", - kind: "cli" + kind: "cli", }, { name: "no-render", type: Boolean, description: "Don't render output.", - kind: "cli" + kind: "cli", }, { name: "alphabetize-properties", type: Boolean, description: "Alphabetize order of class properties.", - kind: "cli" + kind: "cli", }, { name: "all-properties-optional", type: Boolean, description: "Make all class properties optional.", - kind: "cli" + kind: "cli", }, { name: "build-markov-chain", type: String, typeLabel: "FILE", description: "Markov chain corpus filename.", - kind: "cli" + kind: "cli", }, { name: "quiet", type: Boolean, description: "Don't show issues in the generated code.", - kind: "cli" + kind: "cli", }, { name: "debug", @@ -478,29 +553,29 @@ function makeOptionDefinitions(targetLanguages: readonly TargetLanguage[]): Opti typeLabel: "OPTIONS or all", description: "Comma separated debug options: print-graph, print-reconstitution, print-gather-names, print-transformations, print-schema-resolving, print-times, provenance", - kind: "cli" + kind: "cli", }, { name: "telemetry", type: String, typeLabel: "enable|disable", description: "Enable anonymous telemetry to help improve quicktype", - kind: "cli" + kind: "cli", }, { name: "help", alias: "h", type: Boolean, description: "Get some help.", - kind: "cli" + kind: "cli", }, { name: "version", alias: "v", type: Boolean, description: "Display the version of quicktype", - kind: "cli" - } + kind: "cli", + }, ]; return beforeLang.concat(lang, afterLang, inference, afterInference); } @@ -527,41 +602,45 @@ const tableOptionsForOptions: TableOptions = { columns: [ { name: "option", - width: 60 + width: 60, }, { name: "description", - width: 60 - } - ] + width: 60, + }, + ], }; -function makeSectionsBeforeRenderers(targetLanguages: readonly TargetLanguage[]): UsageSection[] { - const langDisplayNames = targetLanguages.map(r => r.displayName).join(", "); +function makeSectionsBeforeRenderers( + targetLanguages: readonly TargetLanguage[], +): UsageSection[] { + const langDisplayNames = targetLanguages + .map((r) => r.displayName) + .join(", "); return [ { 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, + }, ]; } @@ -572,72 +651,101 @@ const sectionsAfterRenderers: UsageSection[] = [ chalk.dim("Generate C# to parse a Bitcoin API"), "$ quicktype -o LatestBlock.cs https://blockchain.info/latestblock", "", - chalk.dim("Generate Go code from a directory of samples containing:"), + chalk.dim( + "Generate Go code from a directory of samples containing:", + ), chalk.dim( ` - Foo.json + 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); } - const targetLanguages = targetLanguage === undefined ? defaultTargetLanguages : [targetLanguage]; + const targetLanguages = + targetLanguage === undefined + ? defaultTargetLanguages + : [targetLanguage]; const optionDefinitions = makeOptionDefinitions(targetLanguages); // We can only fully parse the options once we know which renderer is selected, // because there are renderer-specific options. But we only know which renderer // is selected after we've parsed the options. Hence, we parse the options // twice. This is the first parse to get the renderer: - const incompleteOptions = inferCLIOptions(parseOptions(optionDefinitions, argv, true), targetLanguage); + const incompleteOptions = inferCLIOptions( + parseOptions(optionDefinitions, argv, true), + targetLanguage, + ); if (targetLanguage === undefined) { - const languageName = isLanguageName(incompleteOptions.lang) ? incompleteOptions.lang : "typescript"; + const languageName = isLanguageName(incompleteOptions.lang) + ? incompleteOptions.lang + : "typescript"; targetLanguage = getTargetLanguage(languageName); } - const rendererOptionDefinitions = targetLanguage.cliOptionDefinitions.actual; + const rendererOptionDefinitions = + targetLanguage.cliOptionDefinitions.actual; // Use the global options as well as the renderer options from now on: - const allOptionDefinitions = _.concat(optionDefinitions, rendererOptionDefinitions); + const allOptionDefinitions = _.concat( + optionDefinitions, + rendererOptionDefinitions, + ); // This is the parse that counts: - return inferCLIOptions(parseOptions(allOptionDefinitions, argv, false), targetLanguage); + return inferCLIOptions( + parseOptions(allOptionDefinitions, argv, false), + 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 { +function parseOptions( + definitions: OptionDefinition[], + argv: string[], + partial: boolean, +): Partial { let opts: commandLineArgs.CommandLineOptions; try { opts = commandLineArgs(definitions, { argv, partial }); } catch (e) { assert(!partial, "Partial option parsing should not have failed"); - return messageError("DriverCLIOptionParsingFailed", { message: exceptionToString(e) }); + 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: { [key: string]: unknown; rendererOptions: RendererOptions } = { rendererOptions: {} }; + const options: { + [key: string]: unknown; + rendererOptions: RendererOptions; + } = { rendererOptions: {} }; for (const optionDefinition of definitions) { if (!hasOwnProperty(opts, optionDefinition.name)) { continue; @@ -645,10 +753,16 @@ function parseOptions(definitions: OptionDefinition[], argv: string[], partial: const optionValue = opts[optionDefinition.name] as string; if (optionDefinition.kind !== "cli") { - (options.rendererOptions as Record)[optionDefinition.name] = - optionValue; + ( + options.rendererOptions as Record< + typeof optionDefinition.name, + unknown + > + )[optionDefinition.name] = optionValue; } else { - const k = _.lowerFirst(optionDefinition.name.split("-").map(_.upperFirst).join("")); + const k = _.lowerFirst( + optionDefinition.name.split("-").map(_.upperFirst).join(""), + ); options[k] = optionValue; } } @@ -666,82 +780,121 @@ function usage(targetLanguages: readonly TargetLanguage[]): void { rendererSections.push({ header: `Options for ${language.displayName}`, optionList: definitions, - tableOptions: tableOptionsForOptions + tableOptions: tableOptionsForOptions, }); } - const sections = _.concat(makeSectionsBeforeRenderers(targetLanguages), rendererSections, sectionsAfterRenderers); + const sections = _.concat( + makeSectionsBeforeRenderers(targetLanguages), + rendererSections, + sectionsAfterRenderers, + ); console.log(getUsage(sections)); } // 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); - return topLevels.map(name => [name, jsonMap[name]] as [string, string[]]); - } else if (options.src.length === 0) { - return [[options.topLevel, ["-"]]]; - } else { - return []; + return topLevels.map( + (name) => [name, jsonMap[name]] as [string, string[]], + ); } + if (options.src.length === 0) { + return [[options.topLevel, ["-"]]]; + } + + return []; } -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)]; + return [ + await sourceFromFileOrUrlArray(name, uris, options.httpHeader), + ]; case "schema": - return uris.map(uri => ({ kind: "schema", name, uris: [uri] }) as SchemaTypeSource); + return uris.map( + (uri) => + ({ kind: "schema", name, uris: [uri] }) as SchemaTypeSource, + ); default: - return panic(`typeSourceForURIs must not be called for source language ${options.srcLang}`); + return panic( + `typeSourceForURIs must not be called for source language ${options.srcLang}`, + ); } } 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); const exists = options.src.filter(fs.existsSync); - const directories = exists.filter(x => fs.lstatSync(x).isDirectory()); + const directories = exists.filter((x) => fs.lstatSync(x).isDirectory()); for (const dataDir of directories) { - sources = sources.concat(await samplesFromDirectory(dataDir, options.httpHeader)); + sources = sources.concat( + await samplesFromDirectory(dataDir, options.httpHeader), + ); } // Every src that's not a directory is assumed to be a file or URL - const filesOrUrls = options.src.filter(x => !_.includes(directories, x)); + 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 { - return Object.assign({ kind: "schema" }, schemaForTypeScriptSources(fileNames)) as SchemaTypeSource; + return Object.assign( + { kind: "schema" }, + schemaForTypeScriptSources(fileNames), + ) as SchemaTypeSource; } export function jsonInputForTargetLanguage( targetLanguage: string | TargetLanguage, languages?: TargetLanguage[], - handleJSONRefs = false + handleJSONRefs = false, ): JSONInput { if (typeof targetLanguage === "string") { - const languageName = isLanguageName(targetLanguage) ? targetLanguage : "typescript"; + const languageName = isLanguageName(targetLanguage) + ? targetLanguage + : "typescript"; targetLanguage = defined(languageNamed(languageName, languages)); } - const compressedJSON = new CompressedJSONFromStream(targetLanguage.dateTimeRecognizer, handleJSONRefs); + const compressedJSON = new CompressedJSONFromStream( + targetLanguage.dateTimeRecognizer, + handleJSONRefs, + ); return new JSONInput(compressedJSON); } @@ -750,25 +903,38 @@ async function makeInputData( targetLanguage: TargetLanguage, additionalSchemaAddresses: readonly string[], handleJSONRefs: boolean, - httpHeaders?: string[] + httpHeaders?: string[], ): Promise { const inputData = new InputData(); for (const source of sources) { switch (source.kind) { case "graphql": - await inputData.addSource("graphql", source, () => new GraphQLInput()); + await inputData.addSource( + "graphql", + source, + () => new GraphQLInput(), + ); 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: @@ -779,17 +945,21 @@ 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(sample => stringToStream(sample) as Readable) + samples: src.samples.map( + (sample) => stringToStream(sample) as Readable, + ), }; } export async function makeQuicktypeOptions( options: CLIOptions, - targetLanguages?: TargetLanguage[] + targetLanguages?: TargetLanguage[], ): Promise | undefined> { if (options.help) { usage(targetLanguages ?? defaultTargetLanguages); @@ -821,7 +991,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); @@ -854,9 +1024,18 @@ export async function makeQuicktypeOptions( 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); + 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 }); } @@ -872,13 +1051,17 @@ export async function makeQuicktypeOptions( case "postman": for (const collectionFile of options.src) { const collectionJSON = fs.readFileSync(collectionFile, "utf8"); - const { sources: postmanSources, description } = sourcesFromPostmanCollection( - collectionJSON, - collectionFile - ); + const { sources: postmanSources, description } = + sourcesFromPostmanCollection( + collectionJSON, + collectionFile, + ); for (const src of postmanSources) { sources.push( - Object.assign({ kind: "json" }, stringSourceDataToStreamSourceData(src)) as JSONTypeSource + Object.assign( + { kind: "json" }, + stringSourceDataToStreamSourceData(src), + ) as JSONTypeSource, ); } @@ -893,11 +1076,13 @@ export async function makeQuicktypeOptions( break; default: - return messageError("DriverUnknownSourceLanguage", { lang: options.srcLang }); + return messageError("DriverUnknownSourceLanguage", { + lang: options.srcLang, + }); } - const components = definedMap(options.debug, d => d.split(",")); - const debugAll = components !== undefined && components.includes("all"); + const components = definedMap(options.debug, (d) => d.split(",")); + const debugAll = components?.includes("all"); let debugPrintGraph = debugAll; let checkProvenance = debugAll; let debugPrintReconstitution = debugAll; @@ -923,13 +1108,17 @@ export async function makeQuicktypeOptions( } else if (component === "provenance") { checkProvenance = true; } else if (component !== "all") { - return messageError("DriverUnknownDebugOption", { option: component }); + return messageError("DriverUnknownDebugOption", { + option: component, + }); } } } if (!isLanguageName(options.lang)) { - return messageError("DriverUnknownOutputLanguage", { lang: options.lang }); + return messageError("DriverUnknownOutputLanguage", { + lang: options.lang, + }); } const lang = languageNamed(options.lang, targetLanguages); @@ -949,7 +1138,7 @@ export async function makeQuicktypeOptions( debugPrintGatherNames, debugPrintTransformations, debugPrintSchemaResolving, - debugPrintTimes + debugPrintTimes, }; for (const flagName of inferenceFlagNames) { const cliName = negatedInferenceFlagName(flagName); @@ -966,7 +1155,7 @@ export async function makeQuicktypeOptions( lang, options.additionalSchema, quicktypeOptions.ignoreJsonRefs !== true, - options.httpHeader + options.httpHeader, ); return quicktypeOptions; @@ -974,14 +1163,17 @@ export async function makeQuicktypeOptions( export function writeOutput( cliOptions: CLIOptions, - resultsByFilename: ReadonlyMap + resultsByFilename: ReadonlyMap, ): void { let onFirst = true; for (const [filename, { lines, annotations }] of resultsByFilename) { const output = lines.join("\n"); if (cliOptions.out !== undefined) { - fs.writeFileSync(path.join(path.dirname(cliOptions.out), filename), output); + fs.writeFileSync( + path.join(path.dirname(cliOptions.out), filename), + output, + ); } else { if (!onFirst) { process.stdout.write("\n"); @@ -1003,7 +1195,9 @@ export function writeOutput( if (!(annotation instanceof IssueAnnotationData)) continue; const lineNumber = sa.span.start.line; const humanLineNumber = lineNumber + 1; - console.error(`\nIssue in line ${humanLineNumber}: ${annotation.message}`); + console.error( + `\nIssue in line ${humanLineNumber}: ${annotation.message}`, + ); console.error(`${humanLineNumber}: ${lines[lineNumber]}`); } @@ -1011,7 +1205,9 @@ export function writeOutput( } } -export async function main(args: string[] | Partial): Promise { +export async function main( + args: string[] | Partial, +): Promise { let cliOptions: CLIOptions; if (Array.isArray(args)) { cliOptions = parseCLIOptions(args); @@ -1026,7 +1222,9 @@ export async function main(args: string[] | Partial): Promise case "disable": break; default: - console.error(chalk.red("telemetry must be 'enable' or 'disable'")); + console.error( + chalk.red("telemetry must be 'enable' or 'disable'"), + ); return; } @@ -1037,7 +1235,9 @@ export async function main(args: string[] | Partial): Promise } const quicktypeOptions = await makeQuicktypeOptions(cliOptions); - if (quicktypeOptions === undefined) return; + if (quicktypeOptions === undefined) { + return; + } const resultsByFilename = await quicktypeMultiFile(quicktypeOptions); @@ -1045,7 +1245,7 @@ export async function main(args: string[] | Partial): Promise } if (require.main === module) { - main(process.argv.slice(2)).catch(e => { + main(process.argv.slice(2)).catch((e) => { if (e instanceof Error) { console.error(`Error: ${e.message}.`); } else { diff --git a/test/buildkite.ts b/test/buildkite.ts index 98c8cc12..e0d2ac89 100644 --- a/test/buildkite.ts +++ b/test/buildkite.ts @@ -1,48 +1,65 @@ import * as _ from "lodash"; import { exec } from "shelljs"; -import { WorkItem } from "./test"; -import { allFixtures, Fixture } from "./fixtures"; +import type { WorkItem } from "./test"; +import { allFixtures, type Fixture } from "./fixtures"; function getChangedFiles(base: string, commit: string): string[] { - let diff = exec(`git fetch -v origin ${base} && git diff --name-only origin/${base}..${commit}`).stdout; + const diff = exec( + `git fetch -v origin ${base} && git diff --name-only origin/${base}..${commit}`, + ).stdout; return diff.trim().split("\n"); } -export function affectedFixtures(changedFiles: string[] | undefined = undefined): Fixture[] { +export function affectedFixtures( + changedFiles: string[] | undefined = undefined, +): Fixture[] { if (changedFiles === undefined) { const { GITHUB_BASE_REF: base, GITHUB_SHA: commit } = process.env; - return commit === undefined ? allFixtures : affectedFixtures(getChangedFiles(base || "master", commit)); + return commit === undefined + ? allFixtures + : affectedFixtures(getChangedFiles(base || "master", commit)); } // We can ignore changes in Markdown files - changedFiles = _.reject(changedFiles, file => _.endsWith(file, ".md")); + changedFiles = _.reject(changedFiles, (file) => _.endsWith(file, ".md")); // All fixtures are dirty if any changed file is not included as a sourceFile of some fixture. - const fileDependencies = _.flatMap(allFixtures, f => f.language.sourceFiles || []); - const allFixturesDirty = _.some(changedFiles, f => !_.includes(fileDependencies, f)); + const fileDependencies = _.flatMap( + allFixtures, + (f) => f.language.sourceFiles || [], + ); + const allFixturesDirty = _.some( + changedFiles, + (f) => !_.includes(fileDependencies, f), + ); if (allFixturesDirty) return allFixtures; const dirtyFixtures = allFixtures.filter( - fixture => + (fixture) => // Fixtures that don't specify dependencies are always dirty fixture.language.sourceFiles === undefined || // Fixtures that have a changed file are dirty - _.some(changedFiles, f => _.includes(fixture.language.sourceFiles, f)) + _.some(changedFiles, (f) => + _.includes(fixture.language.sourceFiles, f), + ), ); return dirtyFixtures; } export function divideParallelJobs(workItems: WorkItem[]): WorkItem[] { - const { BUILDKITE_PARALLEL_JOB: pjob, BUILDKITE_PARALLEL_JOB_COUNT: pcount } = process.env; + const { + BUILDKITE_PARALLEL_JOB: pjob, + BUILDKITE_PARALLEL_JOB_COUNT: pcount, + } = process.env; if (pjob === undefined || pcount === undefined) return workItems; try { - const segment = Math.ceil(workItems.length / parseFloat(pcount)); - const start = parseInt(pjob, 10) * segment; + const segment = Math.ceil(workItems.length / Number.parseFloat(pcount)); + const start = Number.parseInt(pjob, 10) * segment; return workItems.slice(start, start + segment); } catch { return workItems; diff --git a/test/fixtures.ts b/test/fixtures.ts index d8279f86..d4eb8f2f 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -1,7 +1,7 @@ import * as _ from "lodash"; -import * as path from "path"; -import * as fs from "fs"; -import { randomBytes } from "crypto"; +import * as path from "node:path"; +import * as fs from "node:fs"; +import { randomBytes } from "node:crypto"; import * as shell from "shelljs"; const Ajv = require("ajv"); @@ -15,16 +15,19 @@ import { inDir, quicktype, quicktypeForLanguage, - Sample, + type Sample, samplesFromSources, testsInDir, - ComparisonArgs, + type ComparisonArgs, mkdirs, - callAndExpectFailure + callAndExpectFailure, } from "./utils"; import * as languages from "./languages"; import type { LanguageName, Option, RendererOptions } from "quicktype-core"; -import { mustNotHappen, defined } from "../packages/quicktype-core/dist/support/Support"; +import { + mustNotHappen, + defined, +} from "../packages/quicktype-core/dist/support/Support"; import { DefaultDateTimeRecognizer } from "../packages/quicktype-core/dist/DateTime"; import chalk from "chalk"; @@ -39,18 +42,31 @@ const MAX_TEST_RUNTIME_MS = 30 * 60 * 1000; * These are tests where we have stringified integers that might be serialized * back as integers, which happens in heterogenous arrays such as ["123", 456]. */ -const testsWithStringifiedIntegers = ["nst-test-suite.json", "kitchen-sink.json"]; +const testsWithStringifiedIntegers = [ + "nst-test-suite.json", + "kitchen-sink.json", +]; -function allowStringifiedIntegers(language: languages.Language, test: string): boolean { +function allowStringifiedIntegers( + language: languages.Language, + test: string, +): boolean { if (language.features.indexOf("integer-string") < 0) return false; return testsWithStringifiedIntegers.indexOf(path.basename(test)) >= 0; } function pathWithoutExtension(fullPath: string, extension: string): string { - return path.join(path.dirname(fullPath), path.basename(fullPath, extension)); + return path.join( + path.dirname(fullPath), + path.basename(fullPath, extension), + ); } -function additionalTestFiles(base: string, extension: string, features: string[] = []): string[] { +function additionalTestFiles( + base: string, + extension: string, + features: string[] = [], +): string[] { const additionalFiles: string[] = []; function tryAdd(filename: string): boolean { if (!fs.existsSync(filename)) return false; @@ -69,7 +85,10 @@ function additionalTestFiles(base: string, extension: string, features: string[] found = tryAdd(fn) || found; for (const feature of features) { - found = tryAdd(`${base}.${i.toString()}.fail.${feature}.${extension}`) || found; + found = + tryAdd( + `${base}.${i.toString()}.fail.${feature}.${extension}`, + ) || found; } found = tryAdd(`${base}.${i.toString()}.fail.${extension}`) || found; @@ -78,12 +97,16 @@ function additionalTestFiles(base: string, extension: string, features: string[] return additionalFiles; } -function runEnvForLanguage(additionalRendererOptions: RendererOptions): NodeJS.ProcessEnv { +function runEnvForLanguage( + additionalRendererOptions: RendererOptions, +): NodeJS.ProcessEnv { const newEnv = Object.assign({}, process.env); for (const option of Object.keys(additionalRendererOptions)) { newEnv["QUICKTYPE_" + option.toUpperCase().replace("-", "_")] = ( - additionalRendererOptions[option as keyof typeof additionalRendererOptions] as Option + additionalRendererOptions[ + option as keyof typeof additionalRendererOptions + ] as Option ).name; } return newEnv; @@ -93,17 +116,20 @@ function comparisonArgs( language: languages.Language, inputFilename: string, expectedFilename: string, - additionalRendererOptions: RendererOptions + additionalRendererOptions: RendererOptions, ): ComparisonArgs { return { expectedFile: expectedFilename, given: { command: defined(language.runCommand)(inputFilename), - env: runEnvForLanguage(additionalRendererOptions) + env: runEnvForLanguage(additionalRendererOptions), }, strict: false, allowMissingNull: language.allowMissingNull, - allowStringifiedIntegers: allowStringifiedIntegers(language, expectedFilename) + allowStringifiedIntegers: allowStringifiedIntegers( + language, + expectedFilename, + ), }; } @@ -117,11 +143,11 @@ function timeEnd(message: string, suffix: string): void { const start = timeMap.get(message); const fullMessage = message + suffix; if (start === undefined) { - console.log(fullMessage + ": " + chalk.red("UNKNOWN TIMING")); + console.log(`${fullMessage}: ${chalk.red("UNKNOWN TIMING")}`); return; } const diff = Date.now() - start; - console.log(fullMessage + `: ${diff} ms`); + console.log(`${fullMessage}: ${diff} ms`); } export abstract class Fixture { @@ -137,21 +163,37 @@ export abstract class Fixture { return; } - abstract getSamples(sources: string[]): { priority: Sample[]; others: Sample[] }; + abstract getSamples(sources: string[]): { + priority: Sample[]; + others: Sample[]; + }; - abstract runWithSample(sample: Sample, index: number, total: number): Promise; + abstract runWithSample( + sample: Sample, + index: number, + total: number, + ): Promise; getRunDirectory(): string { return `test/runs/${this.name}-${randomBytes(3).toString("hex")}`; } - runMessageStart(sample: Sample, index: number, total: number, cwd: string, shouldSkip: boolean): string { - const rendererOptions = _.map(sample.additionalRendererOptions, (v, k) => `${k}: ${v}`).join(", "); + runMessageStart( + sample: Sample, + index: number, + total: number, + cwd: string, + shouldSkip: boolean, + ): string { + const rendererOptions = _.map( + sample.additionalRendererOptions, + (v, k) => `${k}: ${v}`, + ).join(", "); const messageParts = [ - `*`, + "*", chalk.dim(`[${index + 1}/${total}]`), chalk.magenta(this.name) + chalk.dim(`(${rendererOptions})`), - path.join(cwd, chalk.cyan(path.basename(sample.path))) + path.join(cwd, chalk.cyan(path.basename(sample.path))), ]; if (shouldSkip) { messageParts.push(chalk.red("SKIP")); @@ -163,7 +205,12 @@ export abstract class Fixture { runMessageEnd(message: string, numFiles: number) { const numFilesString = ` (${numFiles} files)`; - const suffix = numFiles <= 0 ? chalk.red(numFilesString) : numFiles > 1 ? chalk.green(numFilesString) : ""; + const suffix = + numFiles <= 0 + ? chalk.red(numFilesString) + : numFiles > 1 + ? chalk.green(numFilesString) + : ""; timeEnd(message, suffix); } } @@ -179,7 +226,7 @@ abstract class LanguageFixture extends Fixture { return; } - console.error(`* Setting up`, chalk.magenta(this.name), `fixture`); + console.error(`* Setting up ${chalk.magenta(this.name)} fixture`); await inDir(this.language.base, async () => { await execAsync(setupCommand); @@ -187,11 +234,14 @@ abstract class LanguageFixture extends Fixture { } abstract shouldSkipTest(sample: Sample): boolean; - abstract runQuicktype(filename: string, additionalRendererOptions: RendererOptions): Promise; + abstract runQuicktype( + filename: string, + additionalRendererOptions: RendererOptions, + ): Promise; abstract test( filename: string, additionalRendererOptions: RendererOptions, - additionalFiles: string[] + additionalFiles: string[], ): Promise; additionalFiles(_sample: Sample): string[] { @@ -202,9 +252,17 @@ abstract class LanguageFixture extends Fixture { const cwd = this.getRunDirectory(); const sampleFile = path.resolve(sample.path); const shouldSkip = this.shouldSkipTest(sample); - const additionalFiles = this.additionalFiles(sample).map(p => path.resolve(p)); + const additionalFiles = this.additionalFiles(sample).map((p) => + path.resolve(p), + ); - const message = this.runMessageStart(sample, index, total, cwd, shouldSkip); + const message = this.runMessageStart( + sample, + index, + total, + cwd, + shouldSkip, + ); if (shouldSkip) { return; @@ -218,7 +276,10 @@ abstract class LanguageFixture extends Fixture { let numFiles = -1; await inDir(cwd, async () => { - await this.runQuicktype(sampleFile, sample.additionalRendererOptions); + await this.runQuicktype( + sampleFile, + sample.additionalRendererOptions, + ); if (ONLY_OUTPUT) { return; @@ -226,8 +287,12 @@ abstract class LanguageFixture extends Fixture { try { numFiles = await timeout( - this.test(sampleFile, sample.additionalRendererOptions, additionalFiles), - MAX_TEST_RUNTIME_MS + this.test( + sampleFile, + sample.additionalRendererOptions, + additionalFiles, + ), + MAX_TEST_RUNTIME_MS, ); } catch (e) { failWith("Fixture threw an exception", { error: e, sample }); @@ -236,12 +301,16 @@ abstract class LanguageFixture extends Fixture { // FIXME: This is an ugly hack to exclude Java, which has multiple // output files. We have to support that eventually. - if (sample.saveOutput && OUTPUT_DIR !== undefined && this.language.output.indexOf("/") < 0) { + if ( + sample.saveOutput && + OUTPUT_DIR !== undefined && + this.language.output.indexOf("/") < 0 + ) { const outputDir = path.join( OUTPUT_DIR, this.language.name, path.dirname(sample.path), - path.basename(sample.path, path.extname(sample.path)) + path.basename(sample.path, path.extname(sample.path)), ); mkdirs(outputDir); shell.cp(path.join(cwd, this.language.output), outputDir); @@ -259,7 +328,7 @@ abstract class LanguageFixture extends Fixture { class JSONFixture extends LanguageFixture { constructor( language: languages.Language, - public name: string = language.name + public name: string = language.name, ) { super(language); } @@ -268,15 +337,24 @@ class JSONFixture extends LanguageFixture { return this.name === name || name === "json"; } - async runQuicktype(sample: string, additionalRendererOptions: RendererOptions): Promise { + async runQuicktype( + sample: string, + additionalRendererOptions: RendererOptions, + ): Promise { // FIXME: add options - await quicktypeForLanguage(this.language, sample, "json", true, additionalRendererOptions); + await quicktypeForLanguage( + this.language, + sample, + "json", + true, + additionalRendererOptions, + ); } async test( filename: string, additionalRendererOptions: RendererOptions, - _additionalFiles: string[] + _additionalFiles: string[], ): Promise { if (this.language.compileCommand) { await execAsync(this.language.compileCommand); @@ -285,9 +363,22 @@ class JSONFixture extends LanguageFixture { return 0; } - compareJsonFileToJson(comparisonArgs(this.language, filename, filename, additionalRendererOptions)); + compareJsonFileToJson( + comparisonArgs( + this.language, + filename, + filename, + additionalRendererOptions, + ), + ); - if (this.language.diffViaSchema && !_.includes(this.language.skipDiffViaSchema, path.basename(filename))) { + if ( + this.language.diffViaSchema && + !_.includes( + this.language.skipDiffViaSchema, + path.basename(filename), + ) + ) { debug("* Diffing with code generated via JSON Schema"); // Make a schema await quicktype({ @@ -295,14 +386,23 @@ class JSONFixture extends LanguageFixture { lang: "schema", out: "schema.json", topLevel: this.language.topLevel, - rendererOptions: {} + rendererOptions: {}, }); // Quicktype from the schema and compare to expected code shell.mv(this.language.output, `${this.language.output}.expected`); - await quicktypeForLanguage(this.language, "schema.json", "schema", true, additionalRendererOptions); + await quicktypeForLanguage( + this.language, + "schema.json", + "schema", + true, + additionalRendererOptions, + ); // Compare fixture.output to fixture.output.expected - exec(`diff -Naur ${this.language.output}.expected ${this.language.output} > /dev/null 2>&1`, undefined); + exec( + `diff -Naur ${this.language.output}.expected ${this.language.output} > /dev/null 2>&1`, + undefined, + ); } return 1; @@ -313,10 +413,16 @@ class JSONFixture extends LanguageFixture { return true; } if (this.language.includeJSON !== undefined) { - return !_.includes(this.language.includeJSON, path.basename(sample.path)); + return !_.includes( + this.language.includeJSON, + path.basename(sample.path), + ); } if (this.language.skipJSON !== undefined) { - return _.includes(this.language.skipJSON, path.basename(sample.path)); + return _.includes( + this.language.skipJSON, + path.basename(sample.path), + ); } return false; } @@ -325,45 +431,68 @@ class JSONFixture extends LanguageFixture { // FIXME: this should only run once const prioritySamples = _.concat( testsInDir("test/inputs/json/priority", "json"), - testsInDir("test/inputs/json/samples", "json") + testsInDir("test/inputs/json/samples", "json"), ); - const skipMiscJSON = process.env.QUICKTEST !== undefined || this.language.skipMiscJSON; - const miscSamples = skipMiscJSON ? [] : testsInDir("test/inputs/json/misc", "json"); + const skipMiscJSON = + process.env.QUICKTEST !== undefined || this.language.skipMiscJSON; + const miscSamples = skipMiscJSON + ? [] + : testsInDir("test/inputs/json/misc", "json"); - let { priority, others } = samplesFromSources(sources, prioritySamples, miscSamples, "json"); - - const combinationInputs = _.map([1, 2, 3, 4], n => - _.find(prioritySamples, p => p.endsWith(`/priority/combinations${n}.json`)) + let { priority, others } = samplesFromSources( + sources, + prioritySamples, + miscSamples, + "json", ); - if (combinationInputs.some(p => p === undefined)) { - return failWith("priority/combinations[1234].json samples not found", prioritySamples); + + const combinationInputs = _.map([1, 2, 3, 4], (n) => + _.find(prioritySamples, (p) => + p.endsWith(`/priority/combinations${n}.json`), + ), + ); + if (combinationInputs.some((p) => p === undefined)) { + return failWith( + "priority/combinations[1234].json samples not found", + { prioritySamples }, + ); } if (sources.length === 0 && !ONLY_OUTPUT) { - const quickTestSamples = _.chain(this.language.quickTestRendererOptions) - .flatMap(qt => { + const quickTestSamples = _.chain( + this.language.quickTestRendererOptions, + ) + .flatMap((qt) => { if (Array.isArray(qt)) { const [filename, ro] = qt; - const input = _.find(([] as string[]).concat(prioritySamples, miscSamples), p => - p.endsWith(`/${filename}`) + const input = _.find( + ([] as string[]).concat( + prioritySamples, + miscSamples, + ), + (p) => p.endsWith(`/${filename}`), ); + if (input === undefined) { - return failWith(`quick-test sample ${filename} not found`, qt); + return failWith( + `quick-test sample ${filename} not found`, + { qt }, + ); } return [ { path: input, additionalRendererOptions: ro, - saveOutput: false - } + saveOutput: false, + }, ]; - } else { - return _.map(combinationInputs, p => ({ - path: defined(p), - additionalRendererOptions: qt, - saveOutput: false - })); } + + return _.map(combinationInputs, (p) => ({ + path: defined(p), + additionalRendererOptions: qt, + saveOutput: false, + })); }) .value(); priority = quickTestSamples.concat(priority); @@ -386,7 +515,7 @@ class JSONToXToYFixture extends JSONFixture { languageXOutputFilename: string, rendererOptions: RendererOptions, skipJSON: string[], - language: languages.Language + language: languages.Language, ) { super({ name: languageXName, @@ -404,7 +533,7 @@ class JSONToXToYFixture extends JSONFixture { skipSchema: [], rendererOptions, quickTestRendererOptions: [], - sourceFiles: language.sourceFiles + sourceFiles: language.sourceFiles, }); this.runLanguage = language; this.name = `${this._fixturePrefix}-${language.name}`; @@ -417,7 +546,7 @@ class JSONToXToYFixture extends JSONFixture { async test( filename: string, additionalRendererOptions: RendererOptions, - _additionalFiles: string[] + _additionalFiles: string[], ): Promise { // Generate code for Y from X await quicktypeForLanguage( @@ -425,18 +554,28 @@ class JSONToXToYFixture extends JSONFixture { this.language.output, this.language.name, false, - additionalRendererOptions + additionalRendererOptions, ); // Parse the sample with the code generated from its schema, and compare to the sample - compareJsonFileToJson(comparisonArgs(this.runLanguage, filename, filename, additionalRendererOptions)); + compareJsonFileToJson( + comparisonArgs( + this.runLanguage, + filename, + filename, + additionalRendererOptions, + ), + ); return 1; } shouldSkipTest(sample: Sample): boolean { if (super.shouldSkipTest(sample)) return true; - return _.includes(this.runLanguage.skipJSON, path.basename(sample.path)); + return _.includes( + this.runLanguage.skipJSON, + path.basename(sample.path), + ); } } @@ -452,7 +591,7 @@ class JSONSchemaJSONFixture extends JSONToXToYFixture { "blns-object.json", // AJV refuses to even "compile" the schema we generate "31189.json", // same here "437e7.json", // uri/string confusion - "ed095.json" // same here on Travis + "ed095.json", // same here on Travis ]; super("schema-json", "schema", "schema.json", {}, skipJSON, language); } @@ -460,21 +599,28 @@ class JSONSchemaJSONFixture extends JSONToXToYFixture { async test( filename: string, additionalRendererOptions: RendererOptions, - additionalFiles: string[] + additionalFiles: string[], ): Promise { - let input = JSON.parse(fs.readFileSync(filename, "utf8")); - let schema = JSON.parse(fs.readFileSync(this.language.output, "utf8")); + const input = JSON.parse(fs.readFileSync(filename, "utf8")); + const schema = JSON.parse( + fs.readFileSync(this.language.output, "utf8"), + ); - let ajv = new Ajv({ format: "full", unknownFormats: ["integer", "boolean"] }); + const ajv = new Ajv({ + format: "full", + unknownFormats: ["integer", "boolean"], + }); // Make Ajv's date-time compatible with what we recognize. All non-standard // JSON formats that we use for transformed type kinds must be registered here // with a validation function. // FIXME: Unify this with what's in StringTypes.ts. - ajv.addFormat("date-time", (s: string) => dateTimeRecognizer.isDateTime(s)); - let valid = ajv.validate(schema, input); + ajv.addFormat("date-time", (s: string) => + dateTimeRecognizer.isDateTime(s), + ); + const valid = ajv.validate(schema, input); if (!valid) { failWith("Generated schema does not validate input JSON.", { - filename + filename, }); } @@ -482,19 +628,19 @@ class JSONSchemaJSONFixture extends JSONToXToYFixture { // Generate a schema from the schema, making sure the schemas are the same // FIXME: We could move this to the superclass and test it for all JSON->X->Y - let schemaSchema = "schema-from-schema.json"; + const schemaSchema = "schema-from-schema.json"; await quicktype({ src: [this.language.output], srcLang: this.language.name, lang: this.language.name, topLevel: this.language.topLevel, out: schemaSchema, - rendererOptions: {} + rendererOptions: {}, }); compareJsonFileToJson({ expectedFile: this.language.output, given: { file: schemaSchema }, - strict: true + strict: true, }); return 1; @@ -560,12 +706,19 @@ const skipTypeScriptTests = [ "ed095.json", // top-level is a map "f3139.json", "f3edf.json", - "f466a.json" + "f466a.json", ]; class JSONTypeScriptFixture extends JSONToXToYFixture { constructor(language: languages.Language) { - super("json-ts", "ts", "typescript.ts", { "just-types": "true" }, [], language); + super( + "json-ts", + "ts", + "typescript.ts", + { "just-types": "true" }, + [], + language, + ); } shouldSkipTest(sample: Sample): boolean { @@ -578,7 +731,7 @@ class JSONTypeScriptFixture extends JSONToXToYFixture { class JSONSchemaFixture extends LanguageFixture { constructor( language: languages.Language, - readonly name: string = `schema-${language.name}` + readonly name: string = `schema-${language.name}`, ) { super(language); } @@ -596,8 +749,17 @@ class JSONSchemaFixture extends LanguageFixture { return _.includes(this.language.skipSchema, path.basename(sample.path)); } - async runQuicktype(filename: string, additionalRendererOptions: RendererOptions): Promise { - await quicktypeForLanguage(this.language, filename, "schema", false, additionalRendererOptions); + async runQuicktype( + filename: string, + additionalRendererOptions: RendererOptions, + ): Promise { + await quicktypeForLanguage( + this.language, + filename, + "schema", + false, + additionalRendererOptions, + ); } additionalFiles(sample: Sample): string[] { @@ -608,36 +770,48 @@ class JSONSchemaFixture extends LanguageFixture { async test( _sample: string, additionalRendererOptions: RendererOptions, - additionalFiles: string[] + additionalFiles: string[], ): Promise { if (this.language.compileCommand) { await execAsync(this.language.compileCommand); } if (this.language.runCommand === undefined) return 0; - const failExtensions = this.language.features.map(f => `.fail.${f}.json`).concat([".fail.json"]); + const failExtensions = this.language.features + .map((f) => `.fail.${f}.json`) + .concat([".fail.json"]); for (const filename of additionalFiles) { - if (failExtensions.some(ext => filename.endsWith(ext))) { + if (failExtensions.some((ext) => filename.endsWith(ext))) { callAndExpectFailure( `Expected failure on input ${filename}`, () => exec( defined(this.language.runCommand)(filename), runEnvForLanguage(additionalRendererOptions), - false - ).stdout + false, + ).stdout, ); } else { let expected = filename; for (const feature of this.language.features) { - const featureFilename = filename.replace(".json", `.out.${feature}.json`); + const featureFilename = filename.replace( + ".json", + `.out.${feature}.json`, + ); if (fs.existsSync(featureFilename)) { expected = featureFilename; break; } } - compareJsonFileToJson(comparisonArgs(this.language, filename, expected, additionalRendererOptions)); + compareJsonFileToJson( + comparisonArgs( + this.language, + filename, + expected, + additionalRendererOptions, + ), + ); } } return additionalFiles.length; @@ -647,22 +821,27 @@ class JSONSchemaFixture extends LanguageFixture { function graphQLSchemaFilename(baseName: string): string { const baseMatch = baseName.match(/(.*\D)\d+$/); if (baseMatch === null) { - return failWith("GraphQL test filename does not correspond to naming schema", { baseName }); + return failWith( + "GraphQL test filename does not correspond to naming schema", + { baseName }, + ); } - return baseMatch[1] + ".gqlschema"; + return `${baseMatch[1]}.gqlschema`; } class GraphQLFixture extends LanguageFixture { constructor( language: languages.Language, private readonly _onlyExactName: boolean = false, - readonly name: string = `graphql-${language.name}` + readonly name: string = `graphql-${language.name}`, ) { super(language); } runForName(name: string): boolean { - return this.name === name || (!this._onlyExactName && name === "graphql"); + return ( + this.name === name || (!this._onlyExactName && name === "graphql") + ); } getSamples(sources: string[]): { priority: Sample[]; others: Sample[] } { @@ -674,7 +853,10 @@ class GraphQLFixture extends LanguageFixture { return false; } - async runQuicktype(filename: string, additionalRendererOptions: RendererOptions): Promise { + async runQuicktype( + filename: string, + additionalRendererOptions: RendererOptions, + ): Promise { const baseName = pathWithoutExtension(filename, ".graphql"); const schemaFilename = graphQLSchemaFilename(baseName); await quicktypeForLanguage( @@ -683,7 +865,7 @@ class GraphQLFixture extends LanguageFixture { "graphql", false, additionalRendererOptions, - schemaFilename + schemaFilename, ); } @@ -695,7 +877,7 @@ class GraphQLFixture extends LanguageFixture { async test( _filename: string, additionalRendererOptions: RendererOptions, - additionalFiles: string[] + additionalFiles: string[], ): Promise { if (this.language.compileCommand) { await execAsync(this.language.compileCommand); @@ -703,7 +885,14 @@ class GraphQLFixture extends LanguageFixture { if (this.language.runCommand === undefined) return 0; for (const fn of additionalFiles) { - compareJsonFileToJson(comparisonArgs(this.language, fn, fn, additionalRendererOptions)); + compareJsonFileToJson( + comparisonArgs( + this.language, + fn, + fn, + additionalRendererOptions, + ), + ); } return additionalFiles.length; } @@ -712,7 +901,7 @@ class GraphQLFixture extends LanguageFixture { class CommandSuccessfulLanguageFixture extends LanguageFixture { constructor( language: languages.Language, - public name: string = language.name + public name: string = language.name, ) { super(language); } @@ -721,15 +910,24 @@ class CommandSuccessfulLanguageFixture extends LanguageFixture { return this.name === name || name === "json"; } - async runQuicktype(sample: string, additionalRendererOptions: RendererOptions): Promise { + async runQuicktype( + sample: string, + additionalRendererOptions: RendererOptions, + ): Promise { // FIXME: add options - await quicktypeForLanguage(this.language, sample, "json", true, additionalRendererOptions); + await quicktypeForLanguage( + this.language, + sample, + "json", + true, + additionalRendererOptions, + ); } async test( filename: string, _additionalRendererOptions: RendererOptions, - _additionalFiles: string[] + _additionalFiles: string[], ): Promise { if (this.language.compileCommand) { await execAsync(this.language.compileCommand); @@ -760,44 +958,65 @@ class CommandSuccessfulLanguageFixture extends LanguageFixture { // FIXME: this should only run once const prioritySamples = _.concat( testsInDir("test/inputs/json/priority", "json"), - testsInDir("test/inputs/json/samples", "json") + testsInDir("test/inputs/json/samples", "json"), ); - const miscSamples = this.language.skipMiscJSON ? [] : testsInDir("test/inputs/json/misc", "json"); + const miscSamples = this.language.skipMiscJSON + ? [] + : testsInDir("test/inputs/json/misc", "json"); - let { priority, others } = samplesFromSources(sources, prioritySamples, miscSamples, "json"); - - const combinationInputs = _.map([1, 2, 3, 4], n => - _.find(prioritySamples, p => p.endsWith(`/priority/combinations${n}.json`)) + let { priority, others } = samplesFromSources( + sources, + prioritySamples, + miscSamples, + "json", ); - if (combinationInputs.some(p => p === undefined)) { - return failWith("priority/combinations[1234].json samples not found", prioritySamples); + + const combinationInputs = _.map([1, 2, 3, 4], (n) => + _.find(prioritySamples, (p) => + p.endsWith(`/priority/combinations${n}.json`), + ), + ); + if (combinationInputs.some((p) => p === undefined)) { + return failWith( + "priority/combinations[1234].json samples not found", + { prioritySamples }, + ); } if (sources.length === 0 && !ONLY_OUTPUT) { - const quickTestSamples = _.chain(this.language.quickTestRendererOptions) - .flatMap(qt => { + const quickTestSamples = _.chain( + this.language.quickTestRendererOptions, + ) + .flatMap((qt) => { if (Array.isArray(qt)) { const [filename, ro] = qt; - const input = _.find(([] as string[]).concat(prioritySamples, miscSamples), p => - p.endsWith(`/${filename}`) + const input = _.find( + ([] as string[]).concat( + prioritySamples, + miscSamples, + ), + (p) => p.endsWith(`/${filename}`), ); if (input === undefined) { - return failWith(`quick-test sample ${filename} not found`, qt); + return failWith( + `quick-test sample ${filename} not found`, + { qt }, + ); } return [ { path: input, additionalRendererOptions: ro, - saveOutput: false - } + saveOutput: false, + }, ]; - } else { - return _.map(combinationInputs, p => ({ - path: defined(p), - additionalRendererOptions: qt, - saveOutput: false - })); } + + return _.map(combinationInputs, (p) => ({ + path: defined(p), + additionalRendererOptions: qt, + saveOutput: false, + })); }) .value(); priority = quickTestSamples.concat(priority); @@ -810,9 +1029,15 @@ class CommandSuccessfulLanguageFixture extends LanguageFixture { export const allFixtures: Fixture[] = [ // new JSONFixture(languages.CrystalLanguage), new JSONFixture(languages.CSharpLanguage), - new JSONFixture(languages.CSharpLanguageSystemTextJson, "csharp-SystemTextJson"), + new JSONFixture( + languages.CSharpLanguageSystemTextJson, + "csharp-SystemTextJson", + ), new JSONFixture(languages.JavaLanguage), - new JSONFixture(languages.JavaLanguageWithLegacyDateTime, "java-datetime-legacy"), + new JSONFixture( + languages.JavaLanguageWithLegacyDateTime, + "java-datetime-legacy", + ), new JSONFixture(languages.JavaLanguageWithLombok, "java-lombok"), new JSONFixture(languages.GoLanguage), new JSONFixture(languages.CJSONLanguage), @@ -841,8 +1066,14 @@ export const allFixtures: Fixture[] = [ // new JSONSchemaFixture(languages.CrystalLanguage), new JSONSchemaFixture(languages.CSharpLanguage), new JSONSchemaFixture(languages.JavaLanguage), - new JSONSchemaFixture(languages.JavaLanguageWithLegacyDateTime, "schema-java-datetime-legacy"), - new JSONSchemaFixture(languages.JavaLanguageWithLombok, "schema-java-lombok"), + new JSONSchemaFixture( + languages.JavaLanguageWithLegacyDateTime, + "schema-java-datetime-legacy", + ), + new JSONSchemaFixture( + languages.JavaLanguageWithLombok, + "schema-java-lombok", + ), new JSONSchemaFixture(languages.GoLanguage), new JSONSchemaFixture(languages.CJSONLanguage), new JSONSchemaFixture(languages.CPlusPlusLanguage), @@ -855,7 +1086,10 @@ export const allFixtures: Fixture[] = [ new JSONSchemaFixture(languages.FlowLanguage), new JSONSchemaFixture(languages.JavaScriptLanguage), new JSONSchemaFixture(languages.KotlinLanguage), - new JSONSchemaFixture(languages.KotlinJacksonLanguage, "schema-kotlin-jackson"), + new JSONSchemaFixture( + languages.KotlinJacksonLanguage, + "schema-kotlin-jackson", + ), new JSONSchemaFixture(languages.Scala3Language), new JSONSchemaFixture(languages.DartLanguage), new JSONSchemaFixture(languages.PikeLanguage), @@ -864,8 +1098,16 @@ export const allFixtures: Fixture[] = [ // FIXME: Why are we missing so many language with GraphQL? new GraphQLFixture(languages.CSharpLanguage), new GraphQLFixture(languages.JavaLanguage), - new GraphQLFixture(languages.JavaLanguageWithLegacyDateTime, false, "graphql-java-datetime-legacy"), - new GraphQLFixture(languages.JavaLanguageWithLombok, false, "graphql-java-lombok"), + new GraphQLFixture( + languages.JavaLanguageWithLegacyDateTime, + false, + "graphql-java-datetime-legacy", + ), + new GraphQLFixture( + languages.JavaLanguageWithLombok, + false, + "graphql-java-lombok", + ), new GraphQLFixture(languages.GoLanguage), new GraphQLFixture(languages.CJSONLanguage), new GraphQLFixture(languages.CPlusPlusLanguage), @@ -880,5 +1122,5 @@ export const allFixtures: Fixture[] = [ new GraphQLFixture(languages.HaskellLanguage), new GraphQLFixture(languages.PHPLanguage), new GraphQLFixture(languages.ElixirLanguage), - new CommandSuccessfulLanguageFixture(languages.JavaScriptPropTypesLanguage) + new CommandSuccessfulLanguageFixture(languages.JavaScriptPropTypesLanguage), ]; diff --git a/test/fixtures/csharp-SystemTextJson/.vscode/launch.json b/test/fixtures/csharp-SystemTextJson/.vscode/launch.json index 5143f096..d4083c9b 100644 --- a/test/fixtures/csharp-SystemTextJson/.vscode/launch.json +++ b/test/fixtures/csharp-SystemTextJson/.vscode/launch.json @@ -1,9 +1,9 @@ { - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "version": "0.2.0", - "configurations": [ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ { "name": ".NET Core Launch (console)", "type": "coreclr", @@ -25,4 +25,4 @@ "processId": "${command:pickProcess}" } ] -} \ No newline at end of file +} diff --git a/test/fixtures/csharp-SystemTextJson/.vscode/tasks.json b/test/fixtures/csharp-SystemTextJson/.vscode/tasks.json index 9f439157..472e19d9 100644 --- a/test/fixtures/csharp-SystemTextJson/.vscode/tasks.json +++ b/test/fixtures/csharp-SystemTextJson/.vscode/tasks.json @@ -6,11 +6,9 @@ "tasks": [ { "taskName": "build", - "args": [ - "${workspaceRoot}/test.csproj" - ], + "args": ["${workspaceRoot}/test.csproj"], "isBuildCommand": true, "problemMatcher": "$msCompile" } ] -} \ No newline at end of file +} diff --git a/test/fixtures/csharp/.vscode/launch.json b/test/fixtures/csharp/.vscode/launch.json index 5143f096..d4083c9b 100644 --- a/test/fixtures/csharp/.vscode/launch.json +++ b/test/fixtures/csharp/.vscode/launch.json @@ -1,9 +1,9 @@ { - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "version": "0.2.0", - "configurations": [ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ { "name": ".NET Core Launch (console)", "type": "coreclr", @@ -25,4 +25,4 @@ "processId": "${command:pickProcess}" } ] -} \ No newline at end of file +} diff --git a/test/fixtures/csharp/.vscode/tasks.json b/test/fixtures/csharp/.vscode/tasks.json index 9f439157..472e19d9 100644 --- a/test/fixtures/csharp/.vscode/tasks.json +++ b/test/fixtures/csharp/.vscode/tasks.json @@ -6,11 +6,9 @@ "tasks": [ { "taskName": "build", - "args": [ - "${workspaceRoot}/test.csproj" - ], + "args": ["${workspaceRoot}/test.csproj"], "isBuildCommand": true, "problemMatcher": "$msCompile" } ] -} \ No newline at end of file +} diff --git a/test/fixtures/elm/elm-package.json b/test/fixtures/elm/elm-package.json index f422b20f..d688a53c 100644 --- a/test/fixtures/elm/elm-package.json +++ b/test/fixtures/elm/elm-package.json @@ -3,9 +3,7 @@ "summary": "helpful summary of your project, less than 80 characters", "repository": "https://github.com/user/project.git", "license": "BSD3", - "source-directories": [ - "." - ], + "source-directories": ["."], "exposed-modules": [], "dependencies": { "NoRedInk/elm-decode-pipeline": "3.0.0 <= v < 4.0.0", diff --git a/test/fixtures/elm/runner.js b/test/fixtures/elm/runner.js index 61bdded0..d1c23b79 100644 --- a/test/fixtures/elm/runner.js +++ b/test/fixtures/elm/runner.js @@ -1,13 +1,17 @@ const Elm = require("./elm.js"); const fs = require("fs"); -let ports = Elm.Main.worker().ports; +const ports = Elm.Main.worker().ports; -ports.toJS.subscribe(function(result) { +ports.toJS.subscribe((result) => { if (result.startsWith("Error: ")) { - process.stderr.write(result + "\n", function() { process.exit(1); }); + process.stderr.write(result + "\n", () => { + process.exit(1); + }); } else { - process.stdout.write(result + "\n", function() { process.exit(0); }); + process.stdout.write(result + "\n", () => { + process.exit(0); + }); } }); diff --git a/test/fixtures/flow/main.js b/test/fixtures/flow/main.js index 0911b0b9..0953249f 100644 --- a/test/fixtures/flow/main.js +++ b/test/fixtures/flow/main.js @@ -7,7 +7,7 @@ const fs = require("fs"); const sample = process.argv[2]; const json = fs.readFileSync(sample).toString(); -let value = TopLevel.toTopLevel(json); -let backToJson = TopLevel.topLevelToJson(value); +const value = TopLevel.toTopLevel(json); +const backToJson = TopLevel.topLevelToJson(value); console.log(backToJson); diff --git a/test/fixtures/javascript-prop-types/main.js b/test/fixtures/javascript-prop-types/main.js index 2d98efd5..36febff6 100644 --- a/test/fixtures/javascript-prop-types/main.js +++ b/test/fixtures/javascript-prop-types/main.js @@ -7,10 +7,15 @@ const sample = argv[2]; const json = readFileSync(sample); const obj = JSON.parse(json); -const results = checkPropTypes({ obj: TopLevel }, { obj }, "prop", "MyComponent"); +const results = checkPropTypes( + { obj: TopLevel }, + { obj }, + "prop", + "MyComponent", +); if (results) { - console.log("Failure:", results); + console.log("Failure:", results); } else { - console.log("Success"); + console.log("Success"); } diff --git a/test/fixtures/javascript-prop-types/package.json b/test/fixtures/javascript-prop-types/package.json index f708256f..91b5d9b0 100644 --- a/test/fixtures/javascript-prop-types/package.json +++ b/test/fixtures/javascript-prop-types/package.json @@ -1,15 +1,15 @@ { - "name": "javascript-prop-types", - "version": "0.1.0", - "type": "module", - "description": "Test builds.", - "main": "main.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "Apache-2.0", - "dependencies": { - "check-prop-types": "^1.1.2" - } + "name": "javascript-prop-types", + "version": "0.1.0", + "type": "module", + "description": "Test builds.", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "Apache-2.0", + "dependencies": { + "check-prop-types": "^1.1.2" + } } diff --git a/test/fixtures/javascript/main.js b/test/fixtures/javascript/main.js index f76a027b..cb60dd70 100644 --- a/test/fixtures/javascript/main.js +++ b/test/fixtures/javascript/main.js @@ -6,7 +6,7 @@ const process = require("process"); const sample = process.argv[2]; const json = fs.readFileSync(sample); -let value = TopLevel.toTopLevel(json); -let backToJson = TopLevel.topLevelToJson(value); +const value = TopLevel.toTopLevel(json); +const backToJson = TopLevel.topLevelToJson(value); console.log(backToJson); diff --git a/test/fixtures/kotlin/sample.json b/test/fixtures/kotlin/sample.json index 2745fb5f..aa95faec 100644 --- a/test/fixtures/kotlin/sample.json +++ b/test/fixtures/kotlin/sample.json @@ -1,3 +1,3 @@ { "name": "David" -} \ No newline at end of file +} diff --git a/test/fixtures/objective-c/sample.json b/test/fixtures/objective-c/sample.json index 65685de4..2b49c232 100644 --- a/test/fixtures/objective-c/sample.json +++ b/test/fixtures/objective-c/sample.json @@ -1,1853 +1,1872 @@ - [{ - "id": "6263117491", - "type": "PushEvent", - "actor": { - "id": 12358972, - "login": "CodePipeline-Test", - "display_login": "CodePipeline-Test", - "gravatar_id": "", - "url": "https://api.github.com/users/CodePipeline-Test", - "avatar_url": "https://avatars.githubusercontent.com/u/12358972?" - }, - "repo": { - "id": 63971386, - "name": "CodePipeline-Test/feature-tests", - "url": "https://api.github.com/repos/CodePipeline-Test/feature-tests" - }, - "payload": { - "push_id": 1861573815, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/job-worker-features-V5zkpTEUgBlA4TOEJrWq", - "head": "f283b1955dd88fe65210c842e63408d5ad30d322", - "before": "873d322eb50db0068ae3d0ea2e79cee345e31c93", - "commits": [{ - "sha": "f283b1955dd88fe65210c842e63408d5ad30d322", - "author": { - "email": "CodePipeline-Test@users.noreply.github.com", - "name": "CodePipeline-Test" - }, - "message": "Test commit", - "distinct": true, - "url": "https://api.github.com/repos/CodePipeline-Test/feature-tests/commits/f283b1955dd88fe65210c842e63408d5ad30d322" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:47Z" - }, - { - "id": "6263117489", - "type": "PushEvent", - "actor": { - "id": 16156445, - "login": "JonnyPickard", - "display_login": "JonnyPickard", - "gravatar_id": "", - "url": "https://api.github.com/users/JonnyPickard", - "avatar_url": "https://avatars.githubusercontent.com/u/16156445?" - }, - "repo": { - "id": 97318059, - "name": "JonnyPickard/albums-react-native", - "url": "https://api.github.com/repos/JonnyPickard/albums-react-native" - }, - "payload": { - "push_id": 1861573814, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "a11c7aedf4f1800357864302fe08fc277e9e8652", - "before": "d33e7adbb46926d1d4030d0c855b245062f1d9b5", - "commits": [{ - "sha": "a11c7aedf4f1800357864302fe08fc277e9e8652", - "author": { - "email": "jonathandpickard@gmail.com", - "name": "Jonny Pickard" - }, - "message": "Add basic server to send JSON", - "distinct": true, - "url": "https://api.github.com/repos/JonnyPickard/albums-react-native/commits/a11c7aedf4f1800357864302fe08fc277e9e8652" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:47Z" - }, - { - "id": "6263117487", - "type": "IssueCommentEvent", - "actor": { - "id": 4236651, - "login": "0x53A", - "display_login": "0x53A", - "gravatar_id": "", - "url": "https://api.github.com/users/0x53A", - "avatar_url": "https://avatars.githubusercontent.com/u/4236651?" - }, - "repo": { - "id": 29048891, - "name": "Microsoft/visualfsharp", - "url": "https://api.github.com/repos/Microsoft/visualfsharp" - }, - "payload": { - "action": "created", - "issue": { - "url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335", - "repository_url": "https://api.github.com/repos/Microsoft/visualfsharp", - "labels_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335/labels{/name}", - "comments_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335/comments", - "events_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335/events", - "html_url": "https://github.com/Microsoft/visualfsharp/issues/3335", - "id": 243089775, - "number": 3335, - "title": "[15.3 pre] loading in VS / publish fails if FSharp.Compiler.Tools is imported", - "user": { - "login": "0x53A", - "id": 4236651, - "avatar_url": "https://avatars7.githubusercontent.com/u/4236651?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/0x53A", - "html_url": "https://github.com/0x53A", - "followers_url": "https://api.github.com/users/0x53A/followers", - "following_url": "https://api.github.com/users/0x53A/following{/other_user}", - "gists_url": "https://api.github.com/users/0x53A/gists{/gist_id}", - "starred_url": "https://api.github.com/users/0x53A/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/0x53A/subscriptions", - "organizations_url": "https://api.github.com/users/0x53A/orgs", - "repos_url": "https://api.github.com/users/0x53A/repos", - "events_url": "https://api.github.com/users/0x53A/events{/privacy}", - "received_events_url": "https://api.github.com/users/0x53A/received_events", - "type": "User", - "site_admin": false - }, - "labels": [{ - "id": 308803045, - "url": "https://api.github.com/repos/Microsoft/visualfsharp/labels/Area-CoreCLR", - "name": "Area-CoreCLR", - "color": "5319e7", - "default": false - }], - "state": "closed", - "locked": false, - "assignee": null, - "assignees": [ - - ], - "milestone": { - "url": "https://api.github.com/repos/Microsoft/visualfsharp/milestones/9", - "html_url": "https://github.com/Microsoft/visualfsharp/milestone/9", - "labels_url": "https://api.github.com/repos/Microsoft/visualfsharp/milestones/9/labels", - "id": 2233574, - "number": 9, - "title": "VS 2017 Updates", - "description": "This milestone is for any bug, new feature, or improvement which makes it into a later VS 2017 update.", - "creator": { - "login": "cartermp", - "id": 6309070, - "avatar_url": "https://avatars4.githubusercontent.com/u/6309070?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/cartermp", - "html_url": "https://github.com/cartermp", - "followers_url": "https://api.github.com/users/cartermp/followers", - "following_url": "https://api.github.com/users/cartermp/following{/other_user}", - "gists_url": "https://api.github.com/users/cartermp/gists{/gist_id}", - "starred_url": "https://api.github.com/users/cartermp/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/cartermp/subscriptions", - "organizations_url": "https://api.github.com/users/cartermp/orgs", - "repos_url": "https://api.github.com/users/cartermp/repos", - "events_url": "https://api.github.com/users/cartermp/events{/privacy}", - "received_events_url": "https://api.github.com/users/cartermp/received_events", - "type": "User", - "site_admin": false - }, - "open_issues": 55, - "closed_issues": 158, - "state": "open", - "created_at": "2017-01-06T17:42:02Z", - "updated_at": "2017-07-15T00:13:34Z", - "due_on": null, - "closed_at": null - }, - "comments": 29, - "created_at": "2017-07-14T19:28:04Z", - "updated_at": "2017-07-15T17:06:46Z", - "closed_at": "2017-07-15T00:13:33Z", - "body": "\r\nEdit2: everything works, thanks @KevinRansom \r\n\r\n_Edited_\r\n\r\nI have tried to test if / how a project using paket works in the new world of ``dotnet 2``, comparing C#, F#, and the previous F# sdk (FSharp.NET.Sdk). I have also tested if using F# without paket works.\r\n\r\nHere are four branches, one for each test: https://github.com/0x53A/dotnet-tests.\r\n\r\nResults:\r\n\r\n* paket works with C# and ``Microsoft.NET.Sdk``: https://github.com/0x53A/dotnet-tests/tree/csharp+paket\r\n* paket works with F# when using the 1.x sdk (``FSharp.NET.Sdk``): https://github.com/0x53A/dotnet-tests/tree/fsharp+paket+FSharp.NET.Sdk\r\n* paket ~does NOT~ does work with F# and ``Microsoft.NET.Sdk``: https://github.com/0x53A/dotnet-tests/tree/fsharp+paket\r\n* using F# with ``Microsoft.NET.Sdk`` and nuget does work: https://github.com/0x53A/dotnet-tests/tree/fsharp+nuget\r\n\r\nThe paket version I have tested this with is ``5.6.12``.\r\n\r\nIt is kind of funny that C# seems to work flawlessly with paket." - }, - "comment": { - "url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/comments/315547940", - "html_url": "https://github.com/Microsoft/visualfsharp/issues/3335#issuecomment-315547940", - "issue_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335", - "id": 315547940, - "user": { - "login": "0x53A", - "id": 4236651, - "avatar_url": "https://avatars7.githubusercontent.com/u/4236651?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/0x53A", - "html_url": "https://github.com/0x53A", - "followers_url": "https://api.github.com/users/0x53A/followers", - "following_url": "https://api.github.com/users/0x53A/following{/other_user}", - "gists_url": "https://api.github.com/users/0x53A/gists{/gist_id}", - "starred_url": "https://api.github.com/users/0x53A/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/0x53A/subscriptions", - "organizations_url": "https://api.github.com/users/0x53A/orgs", - "repos_url": "https://api.github.com/users/0x53A/repos", - "events_url": "https://api.github.com/users/0x53A/events{/privacy}", - "received_events_url": "https://api.github.com/users/0x53A/received_events", - "type": "User", - "site_admin": false - }, - "created_at": "2017-07-15T17:06:46Z", - "updated_at": "2017-07-15T17:06:46Z", - "body": "3) DisableImplicitFSharpCoreReference and paket\r\n\r\npaket.dependencies:\r\n\r\n```nuget FSharp.Core 4.0.0.1```\r\n\r\n```Xml\r\n\r\n \r\n net461\r\n true\r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n\r\n=>\r\n\r\n```\r\nC:\\source\\dotnet-tests>dotnet publish\r\nMicrosoft (R) Build Engine version 15.3.406.54721 for .NET Core\r\nCopyright (C) Microsoft Corporation. All rights reserved.\r\n\r\nC:\\source\\dotnet-tests\\Library.fs(7,17): error FS0039: The value, namespace, type or module 'Result' is not defined. [C:\\source\\dotnet-tests\\paket-fsharp-test.fsproj]\r\nC:\\source\\dotnet-tests\\Library.fs(8,42): error FS0039: The pattern discriminator 'Ok' is not defined. [C:\\source\\dotnet-tests\\paket-fsharp-test.fsproj]\r\n```\r\n\r\nwhich is good.\r\n\r\n-----------------\r\n\r\nSo it looks like both properties work as expected. It seems that in __2)__ the compiler automagically referenced some FSharp.Core, because none was explicitly referenced." - } - }, - "public": true, - "created_at": "2017-07-15T17:06:47Z", - "org": { - "id": 6154722, - "login": "Microsoft", - "gravatar_id": "", - "url": "https://api.github.com/orgs/Microsoft", - "avatar_url": "https://avatars.githubusercontent.com/u/6154722?" - } - }, - { - "id": "6263117486", - "type": "PushEvent", - "actor": { - "id": 982267, - "login": "gxela", - "display_login": "gxela", - "gravatar_id": "", - "url": "https://api.github.com/users/gxela", - "avatar_url": "https://avatars.githubusercontent.com/u/982267?" - }, - "repo": { - "id": 97197951, - "name": "AudioBible/AudioBible.life", - "url": "https://api.github.com/repos/AudioBible/AudioBible.life" - }, - "payload": { - "push_id": 1861573811, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "31e079597959be78850e06c623383d522f8fe283", - "before": "11d32ac0eb7051ddc7da05dab183f10ed861fa61", - "commits": [{ - "sha": "31e079597959be78850e06c623383d522f8fe283", - "author": { - "email": "alex@goretoy.com", - "name": "Alex Goretoy" - }, - "message": "update", - "distinct": true, - "url": "https://api.github.com/repos/AudioBible/AudioBible.life/commits/31e079597959be78850e06c623383d522f8fe283" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:47Z", - "org": { - "id": 29329308, - "login": "AudioBible", - "gravatar_id": "", - "url": "https://api.github.com/orgs/AudioBible", - "avatar_url": "https://avatars.githubusercontent.com/u/29329308?" - } - }, - { - "id": "6263117481", - "type": "CreateEvent", - "actor": { - "id": 998519, - "login": "martinstabe", - "display_login": "martinstabe", - "gravatar_id": "", - "url": "https://api.github.com/users/martinstabe", - "avatar_url": "https://avatars.githubusercontent.com/u/998519?" - }, - "repo": { - "id": 90621389, - "name": "ft-interactive/archive", - "url": "https://api.github.com/repos/ft-interactive/archive" - }, - "payload": { - "ref": "personal-data", - "ref_type": "branch", - "master_branch": "master", - "description": "Refactored versions of a few older FT interactive stories", - "pusher_type": "user" - }, - "public": true, - "created_at": "2017-07-15T17:06:47Z", - "org": { - "id": 2511089, - "login": "ft-interactive", - "gravatar_id": "", - "url": "https://api.github.com/orgs/ft-interactive", - "avatar_url": "https://avatars.githubusercontent.com/u/2511089?" - } - }, - { - "id": "6263117480", - "type": "PushEvent", - "actor": { - "id": 30200303, - "login": "musikdusche", - "display_login": "musikdusche", - "gravatar_id": "", - "url": "https://api.github.com/users/musikdusche", - "avatar_url": "https://avatars.githubusercontent.com/u/30200303?" - }, - "repo": { - "id": 97330240, - "name": "musikdusche/hello-world", - "url": "https://api.github.com/repos/musikdusche/hello-world" - }, - "payload": { - "push_id": 1861573809, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/readmeworks", - "head": "e09f4ef810382578be4ba49bcc351c94ac8b15f9", - "before": "10f052d3f22eaad13302b5e0e6d1a4af77a73f91", - "commits": [{ - "sha": "e09f4ef810382578be4ba49bcc351c94ac8b15f9", - "author": { - "email": "f.toens@gmx.de", - "name": "musikdusche" - }, - "message": "Update README.md\n\ntrying out markdown syntaxes", - "distinct": true, - "url": "https://api.github.com/repos/musikdusche/hello-world/commits/e09f4ef810382578be4ba49bcc351c94ac8b15f9" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:47Z" - }, - { - "id": "6263117478", - "type": "PushEvent", - "actor": { - "id": 4712642, - "login": "neu-rah", - "display_login": "neu-rah", - "gravatar_id": "", - "url": "https://api.github.com/users/neu-rah", - "avatar_url": "https://avatars.githubusercontent.com/u/4712642?" - }, - "repo": { - "id": 23024191, - "name": "neu-rah/ArduinoMenu", - "url": "https://api.github.com/repos/neu-rah/ArduinoMenu" - }, - "payload": { - "push_id": 1861573808, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "1557e3155279ca19e35048f8a6758189cbb2231a", - "before": "fb1b8c70b324bf73231728a708fe496991c51607", - "commits": [{ - "sha": "1557e3155279ca19e35048f8a6758189cbb2231a", - "author": { - "email": "ruihfazevedo@gmail.com", - "name": "Rui Azevedo" - }, - "message": "remove pin collision between encoder and serial on I2C example as noted by Paul Gaertner", - "distinct": true, - "url": "https://api.github.com/repos/neu-rah/ArduinoMenu/commits/1557e3155279ca19e35048f8a6758189cbb2231a" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:47Z" - }, - { - "id": "6263117476", - "type": "PushEvent", - "actor": { - "id": 22308572, - "login": "zfang399", - "display_login": "zfang399", - "gravatar_id": "", - "url": "https://api.github.com/users/zfang399", - "avatar_url": "https://avatars.githubusercontent.com/u/22308572?" - }, - "repo": { - "id": 93472978, - "name": "zfang399/LeetCode-Problems", - "url": "https://api.github.com/repos/zfang399/LeetCode-Problems" - }, - "payload": { - "push_id": 1861573807, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "dffd54fc9872b0a14ae7b3089c541db439c77dc6", - "before": "31643c5f628a91714dabf3c0472d6b3b6f2d75f9", - "commits": [{ - "sha": "dffd54fc9872b0a14ae7b3089c541db439c77dc6", - "author": { - "email": "zfang@nd.edu", - "name": "Zhaoyuan Fang" - }, - "message": "Reverse Linked List II", - "distinct": true, - "url": "https://api.github.com/repos/zfang399/LeetCode-Problems/commits/dffd54fc9872b0a14ae7b3089c541db439c77dc6" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z" - }, - { - "id": "6263117475", - "type": "PushEvent", - "actor": { - "id": 4750766, - "login": "rohintangirala", - "display_login": "rohintangirala", - "gravatar_id": "", - "url": "https://api.github.com/users/rohintangirala", - "avatar_url": "https://avatars.githubusercontent.com/u/4750766?" - }, - "repo": { - "id": 97284340, - "name": "Twenty-App/Twenty-App.github.io", - "url": "https://api.github.com/repos/Twenty-App/Twenty-App.github.io" - }, - "payload": { - "push_id": 1861573806, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "90effa1defcc57fbb19d118a3cf773e200542333", - "before": "a3a94db8f23bec183df701cc6f27b761be8f6250", - "commits": [{ - "sha": "90effa1defcc57fbb19d118a3cf773e200542333", - "author": { - "email": "rohinkt@gmail.com", - "name": "Rohin Tangirala" - }, - "message": "Set theme jekyll-theme-tactile", - "distinct": true, - "url": "https://api.github.com/repos/Twenty-App/Twenty-App.github.io/commits/90effa1defcc57fbb19d118a3cf773e200542333" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z", - "org": { - "id": 30188091, - "login": "Twenty-App", - "gravatar_id": "", - "url": "https://api.github.com/orgs/Twenty-App", - "avatar_url": "https://avatars.githubusercontent.com/u/30188091?" - } - }, - { - "id": "6263117473", - "type": "PushEvent", - "actor": { - "id": 8517910, - "login": "LombiqBot", - "display_login": "LombiqBot", - "gravatar_id": "", - "url": "https://api.github.com/users/LombiqBot", - "avatar_url": "https://avatars.githubusercontent.com/u/8517910?" - }, - "repo": { - "id": 46594739, - "name": "Lombiq/Associativy-Taxonomies-Adapter", - "url": "https://api.github.com/repos/Lombiq/Associativy-Taxonomies-Adapter" - }, - "payload": { - "push_id": 1861573805, - "size": 0, - "distinct_size": 0, - "ref": "refs/heads/orchard-upgrade-1.10", - "head": "e1d77dd00dfdc65d5d84b1712be94e609273c838", - "before": "e1d77dd00dfdc65d5d84b1712be94e609273c838", - "commits": [ - - ] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z", - "org": { - "id": 8158177, - "login": "Lombiq", - "gravatar_id": "", - "url": "https://api.github.com/orgs/Lombiq", - "avatar_url": "https://avatars.githubusercontent.com/u/8158177?" - } - }, - { - "id": "6263117472", - "type": "PushEvent", - "actor": { - "id": 25966, - "login": "reconbot", - "display_login": "reconbot", - "gravatar_id": "", - "url": "https://api.github.com/users/reconbot", - "avatar_url": "https://avatars.githubusercontent.com/u/25966?" - }, - "repo": { - "id": 893522, - "name": "EmergingTechnologyAdvisors/node-serialport", - "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport" - }, - "payload": { - "push_id": 1861573804, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a", - "before": "2361fa599a16a10ad07ffe863fe00bb2bc75d29a", - "commits": [{ - "sha": "9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a", - "author": { - "email": "wizard@roborooter.com", - "name": "Francis Gulotta" - }, - "message": "[unix] Move setting up the baudrate to the end of the open()\n\n- Test 1000000 baud", - "distinct": true, - "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/commits/9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z", - "org": { - "id": 8947774, - "login": "EmergingTechnologyAdvisors", - "gravatar_id": "", - "url": "https://api.github.com/orgs/EmergingTechnologyAdvisors", - "avatar_url": "https://avatars.githubusercontent.com/u/8947774?" - } - }, - { - "id": "6263117471", - "type": "IssueCommentEvent", - "actor": { - "id": 737750, - "login": "samuelkarp", - "display_login": "samuelkarp", - "gravatar_id": "", - "url": "https://api.github.com/users/samuelkarp", - "avatar_url": "https://avatars.githubusercontent.com/u/737750?" - }, - "repo": { - "id": 59514412, - "name": "awslabs/amazon-ecr-credential-helper", - "url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper" - }, - "payload": { - "action": "created", - "issue": { - "url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49", - "repository_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper", - "labels_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49/labels{/name}", - "comments_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49/comments", - "events_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49/events", - "html_url": "https://github.com/awslabs/amazon-ecr-credential-helper/issues/49", - "id": 241526602, - "number": 49, - "title": "no basic auth credentials yet AWS CLI has access", - "user": { - "login": "guyisra", - "id": 1073521, - "avatar_url": "https://avatars5.githubusercontent.com/u/1073521?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/guyisra", - "html_url": "https://github.com/guyisra", - "followers_url": "https://api.github.com/users/guyisra/followers", - "following_url": "https://api.github.com/users/guyisra/following{/other_user}", - "gists_url": "https://api.github.com/users/guyisra/gists{/gist_id}", - "starred_url": "https://api.github.com/users/guyisra/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/guyisra/subscriptions", - "organizations_url": "https://api.github.com/users/guyisra/orgs", - "repos_url": "https://api.github.com/users/guyisra/repos", - "events_url": "https://api.github.com/users/guyisra/events{/privacy}", - "received_events_url": "https://api.github.com/users/guyisra/received_events", - "type": "User", - "site_admin": false - }, - "labels": [ - - ], - "state": "open", - "locked": false, - "assignee": null, - "assignees": [ - - ], - "milestone": null, - "comments": 3, - "created_at": "2017-07-09T13:59:15Z", - "updated_at": "2017-07-15T17:06:46Z", - "closed_at": null, - "body": "I am using Docker v17 and for some reason when trying to push to ECR I get no basic auth credentials.\r\n\r\nThis doesn't happen if I manually login with `aws ecr get-login ...`\r\n\r\nthe policy is configured correctly, I can run other AWS commands.\r\nIt gives the same response with either a profile with the proper policy or with the access key and secret explicitly set.." - }, - "comment": { - "url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/comments/315547939", - "html_url": "https://github.com/awslabs/amazon-ecr-credential-helper/issues/49#issuecomment-315547939", - "issue_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49", - "id": 315547939, - "user": { - "login": "samuelkarp", - "id": 737750, - "avatar_url": "https://avatars7.githubusercontent.com/u/737750?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/samuelkarp", - "html_url": "https://github.com/samuelkarp", - "followers_url": "https://api.github.com/users/samuelkarp/followers", - "following_url": "https://api.github.com/users/samuelkarp/following{/other_user}", - "gists_url": "https://api.github.com/users/samuelkarp/gists{/gist_id}", - "starred_url": "https://api.github.com/users/samuelkarp/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/samuelkarp/subscriptions", - "organizations_url": "https://api.github.com/users/samuelkarp/orgs", - "repos_url": "https://api.github.com/users/samuelkarp/repos", - "events_url": "https://api.github.com/users/samuelkarp/events{/privacy}", - "received_events_url": "https://api.github.com/users/samuelkarp/received_events", - "type": "User", - "site_admin": false - }, - "created_at": "2017-07-15T17:06:46Z", - "updated_at": "2017-07-15T17:06:46Z", - "body": "@mskutin Thanks for providing the log; that's very helpful. Can you let me know what region this was for so I can investigate further?" - } - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z", - "org": { - "id": 3299148, - "login": "awslabs", - "gravatar_id": "", - "url": "https://api.github.com/orgs/awslabs", - "avatar_url": "https://avatars.githubusercontent.com/u/3299148?" - } - }, - { - "id": "6263117468", - "type": "IssueCommentEvent", - "actor": { - "id": 1645308, - "login": "almereyda", - "display_login": "almereyda", - "gravatar_id": "", - "url": "https://api.github.com/users/almereyda", - "avatar_url": "https://avatars.githubusercontent.com/u/1645308?" - }, - "repo": { - "id": 22657662, - "name": "wsargent/docker-cheat-sheet", - "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet" - }, - "payload": { - "action": "created", - "issue": { - "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136", - "repository_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet", - "labels_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136/labels{/name}", - "comments_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136/comments", - "events_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136/events", - "html_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136", - "id": 243181907, - "number": 136, - "title": "Volumes can be files", - "user": { - "login": "phoen1x", - "id": 2550793, - "avatar_url": "https://avatars7.githubusercontent.com/u/2550793?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/phoen1x", - "html_url": "https://github.com/phoen1x", - "followers_url": "https://api.github.com/users/phoen1x/followers", - "following_url": "https://api.github.com/users/phoen1x/following{/other_user}", - "gists_url": "https://api.github.com/users/phoen1x/gists{/gist_id}", - "starred_url": "https://api.github.com/users/phoen1x/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/phoen1x/subscriptions", - "organizations_url": "https://api.github.com/users/phoen1x/orgs", - "repos_url": "https://api.github.com/users/phoen1x/repos", - "events_url": "https://api.github.com/users/phoen1x/events{/privacy}", - "received_events_url": "https://api.github.com/users/phoen1x/received_events", - "type": "User", - "site_admin": false - }, - "labels": [ - - ], - "state": "open", - "locked": false, - "assignee": null, - "assignees": [ - - ], - "milestone": null, - "comments": 0, - "created_at": "2017-07-15T15:28:10Z", - "updated_at": "2017-07-15T17:06:46Z", - "closed_at": null, - "pull_request": { - "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/pulls/136", - "html_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136", - "diff_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136.diff", - "patch_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136.patch" - }, - "body": "Just wanted to add that is possible to mount files as volumes. \r\n\r\nDon't know if that is worth mentioning. But it can be useful if you want to toy around with a image from [Docker Hub](https://hub.docker.com) without writing your own Dockerfile." - }, - "comment": { - "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/comments/315547938", - "html_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136#issuecomment-315547938", - "issue_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136", - "id": 315547938, - "user": { - "login": "almereyda", - "id": 1645308, - "avatar_url": "https://avatars4.githubusercontent.com/u/1645308?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/almereyda", - "html_url": "https://github.com/almereyda", - "followers_url": "https://api.github.com/users/almereyda/followers", - "following_url": "https://api.github.com/users/almereyda/following{/other_user}", - "gists_url": "https://api.github.com/users/almereyda/gists{/gist_id}", - "starred_url": "https://api.github.com/users/almereyda/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/almereyda/subscriptions", - "organizations_url": "https://api.github.com/users/almereyda/orgs", - "repos_url": "https://api.github.com/users/almereyda/repos", - "events_url": "https://api.github.com/users/almereyda/events{/privacy}", - "received_events_url": "https://api.github.com/users/almereyda/received_events", - "type": "User", - "site_admin": false - }, - "created_at": "2017-07-15T17:06:46Z", - "updated_at": "2017-07-15T17:06:46Z", - "body": "Indeed, I do that all the time when modifying assets that were turned into immutable images already." - } - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z" - }, - { - "id": "6263117464", - "type": "PushEvent", - "actor": { - "id": 19437824, - "login": "keriwheatley", - "display_login": "keriwheatley", - "gravatar_id": "", - "url": "https://api.github.com/users/keriwheatley", - "avatar_url": "https://avatars.githubusercontent.com/u/19437824?" - }, - "repo": { - "id": 91394098, - "name": "keriwheatley/coursework", - "url": "https://api.github.com/repos/keriwheatley/coursework" - }, - "payload": { - "push_id": 1861573800, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "490f194beb4be216ed955d187aee265443dd532c", - "before": "14034277c8e715f9988686d85701b501845705e7", - "commits": [{ - "sha": "490f194beb4be216ed955d187aee265443dd532c", - "author": { - "email": "keri.wheatley@civitaslearning.com", - "name": "Keri Wheatley" - }, - "message": "updates to twitter_popularity", - "distinct": true, - "url": "https://api.github.com/repos/keriwheatley/coursework/commits/490f194beb4be216ed955d187aee265443dd532c" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z" - }, - { - "id": "6263117462", - "type": "CreateEvent", - "actor": { - "id": 12358972, - "login": "CodePipeline-Test", - "display_login": "CodePipeline-Test", - "gravatar_id": "", - "url": "https://api.github.com/users/CodePipeline-Test", - "avatar_url": "https://avatars.githubusercontent.com/u/12358972?" - }, - "repo": { - "id": 63971386, - "name": "CodePipeline-Test/feature-tests", - "url": "https://api.github.com/repos/CodePipeline-Test/feature-tests" - }, - "payload": { - "ref": "job-worker-features-V5zkpTEUgBlA4TOEJrWq", - "ref_type": "branch", - "master_branch": "master", - "description": "for feature tests", - "pusher_type": "user" - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z" - }, - { - "id": "6263117460", - "type": "WatchEvent", - "actor": { - "id": 9091565, - "login": "chiprunner1995", - "display_login": "chiprunner1995", - "gravatar_id": "", - "url": "https://api.github.com/users/chiprunner1995", - "avatar_url": "https://avatars.githubusercontent.com/u/9091565?" - }, - "repo": { - "id": 308512, - "name": "psake/psake", - "url": "https://api.github.com/repos/psake/psake" - }, - "payload": { - "action": "started" - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z", - "org": { - "id": 1007585, - "login": "psake", - "gravatar_id": "", - "url": "https://api.github.com/orgs/psake", - "avatar_url": "https://avatars.githubusercontent.com/u/1007585?" - } - }, - { - "id": "6263117459", - "type": "PushEvent", - "actor": { - "id": 30199151, - "login": "Geoffers888", - "display_login": "Geoffers888", - "gravatar_id": "", - "url": "https://api.github.com/users/Geoffers888", - "avatar_url": "https://avatars.githubusercontent.com/u/30199151?" - }, - "repo": { - "id": 97330344, - "name": "Geoffers888/Console-Boxes", - "url": "https://api.github.com/repos/Geoffers888/Console-Boxes" - }, - "payload": { - "push_id": 1861573799, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "46f85052c269c7ede354a698e05e5ef5359bc71b", - "before": "ecb8a45cc1e49ee60ffa880eba8219b294ec44f5", - "commits": [{ - "sha": "46f85052c269c7ede354a698e05e5ef5359bc71b", - "author": { - "email": "geoff.cowin@gmail.com", - "name": "Geoffers888" - }, - "message": "Create README.md", - "distinct": true, - "url": "https://api.github.com/repos/Geoffers888/Console-Boxes/commits/46f85052c269c7ede354a698e05e5ef5359bc71b" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z" - }, - { - "id": "6263117454", - "type": "PushEvent", - "actor": { - "id": 8517910, - "login": "LombiqBot", - "display_login": "LombiqBot", - "gravatar_id": "", - "url": "https://api.github.com/users/LombiqBot", - "avatar_url": "https://avatars.githubusercontent.com/u/8517910?" - }, - "repo": { - "id": 46624662, - "name": "Lombiq/Orchard-External-Pages", - "url": "https://api.github.com/repos/Lombiq/Orchard-External-Pages" - }, - "payload": { - "push_id": 1861573796, - "size": 0, - "distinct_size": 0, - "ref": "refs/heads/issue/OSOE-7", - "head": "a630eb8494f07e6f11a5bc396a0829d5aa690c5f", - "before": "a630eb8494f07e6f11a5bc396a0829d5aa690c5f", - "commits": [ - - ] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z", - "org": { - "id": 8158177, - "login": "Lombiq", - "gravatar_id": "", - "url": "https://api.github.com/orgs/Lombiq", - "avatar_url": "https://avatars.githubusercontent.com/u/8158177?" - } - }, - { - "id": "6263117451", - "type": "PullRequestEvent", - "actor": { - "id": 25966, - "login": "reconbot", - "display_login": "reconbot", - "gravatar_id": "", - "url": "https://api.github.com/users/reconbot", - "avatar_url": "https://avatars.githubusercontent.com/u/25966?" - }, - "repo": { - "id": 893522, - "name": "EmergingTechnologyAdvisors/node-serialport", - "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport" - }, - "payload": { - "action": "closed", - "number": 1235, - "pull_request": { - "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235", - "id": 130722112, - "html_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235", - "diff_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235.diff", - "patch_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235.patch", - "issue_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235", - "number": 1235, - "state": "closed", - "locked": false, - "title": "[unix] Move setting up the baudrate to the end of the open() to better support custom baudrates", - "user": { - "login": "reconbot", - "id": 25966, - "avatar_url": "https://avatars6.githubusercontent.com/u/25966?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/reconbot", - "html_url": "https://github.com/reconbot", - "followers_url": "https://api.github.com/users/reconbot/followers", - "following_url": "https://api.github.com/users/reconbot/following{/other_user}", - "gists_url": "https://api.github.com/users/reconbot/gists{/gist_id}", - "starred_url": "https://api.github.com/users/reconbot/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/reconbot/subscriptions", - "organizations_url": "https://api.github.com/users/reconbot/orgs", - "repos_url": "https://api.github.com/users/reconbot/repos", - "events_url": "https://api.github.com/users/reconbot/events{/privacy}", - "received_events_url": "https://api.github.com/users/reconbot/received_events", - "type": "User", - "site_admin": false - }, - "body": "- Test 1000000 baud\r\n\r\ncloses #1077", - "created_at": "2017-07-15T16:53:28Z", - "updated_at": "2017-07-15T17:06:45Z", - "closed_at": "2017-07-15T17:06:45Z", - "merged_at": "2017-07-15T17:06:45Z", - "merge_commit_sha": "9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a", - "assignee": null, - "assignees": [ - - ], - "requested_reviewers": [ - - ], - "milestone": null, - "commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/commits", - "review_comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/comments", - "review_comment_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235/comments", - "statuses_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/e57b3d685f6497ebe8669ce8b05894bacd895177", - "head": { - "label": "EmergingTechnologyAdvisors:1000000-baud", - "ref": "1000000-baud", - "sha": "e57b3d685f6497ebe8669ce8b05894bacd895177", - "user": { - "login": "EmergingTechnologyAdvisors", - "id": 8947774, - "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/EmergingTechnologyAdvisors", - "html_url": "https://github.com/EmergingTechnologyAdvisors", - "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", - "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", - "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", - "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", - "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", - "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", - "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", - "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", - "type": "Organization", - "site_admin": false - }, - "repo": { - "id": 893522, - "name": "node-serialport", - "full_name": "EmergingTechnologyAdvisors/node-serialport", - "owner": { - "login": "EmergingTechnologyAdvisors", - "id": 8947774, - "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/EmergingTechnologyAdvisors", - "html_url": "https://github.com/EmergingTechnologyAdvisors", - "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", - "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", - "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", - "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", - "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", - "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", - "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", - "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", - "type": "Organization", - "site_admin": false - }, - "private": false, - "html_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", - "description": "Node.js package to access serial ports for reading and writing. Welcome your robotic JavaScript overlords. Better yet, program them!", - "fork": false, - "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport", - "forks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/forks", - "keys_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/keys{/key_id}", - "collaborators_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/collaborators{/collaborator}", - "teams_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/teams", - "hooks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/hooks", - "issue_events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/events{/number}", - "events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/events", - "assignees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/assignees{/user}", - "branches_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/branches{/branch}", - "tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/tags", - "blobs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/blobs{/sha}", - "git_tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/tags{/sha}", - "git_refs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/refs{/sha}", - "trees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/trees{/sha}", - "statuses_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/{sha}", - "languages_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/languages", - "stargazers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/stargazers", - "contributors_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contributors", - "subscribers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscribers", - "subscription_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscription", - "commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/commits{/sha}", - "git_commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/commits{/sha}", - "comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/comments{/number}", - "issue_comment_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/comments{/number}", - "contents_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contents/{+path}", - "compare_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/compare/{base}...{head}", - "merges_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/merges", - "archive_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/{archive_format}{/ref}", - "downloads_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/downloads", - "issues_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues{/number}", - "pulls_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls{/number}", - "milestones_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/milestones{/number}", - "notifications_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/notifications{?since,all,participating}", - "labels_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/labels{/name}", - "releases_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/releases{/id}", - "deployments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/deployments", - "created_at": "2010-09-07T12:24:28Z", - "updated_at": "2017-07-14T16:30:58Z", - "pushed_at": "2017-07-15T17:06:45Z", - "git_url": "git://github.com/EmergingTechnologyAdvisors/node-serialport.git", - "ssh_url": "git@github.com:EmergingTechnologyAdvisors/node-serialport.git", - "clone_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport.git", - "svn_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", - "homepage": "", - "size": 1914, - "stargazers_count": 2829, - "watchers_count": 2829, - "language": "JavaScript", - "has_issues": true, - "has_projects": true, - "has_downloads": true, - "has_wiki": false, - "has_pages": true, - "forks_count": 601, - "mirror_url": null, - "open_issues_count": 30, - "forks": 601, - "open_issues": 30, - "watchers": 2829, - "default_branch": "master" - } - }, - "base": { - "label": "EmergingTechnologyAdvisors:master", - "ref": "master", - "sha": "ee7315f59c7698811f4f76405383f18680843926", - "user": { - "login": "EmergingTechnologyAdvisors", - "id": 8947774, - "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/EmergingTechnologyAdvisors", - "html_url": "https://github.com/EmergingTechnologyAdvisors", - "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", - "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", - "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", - "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", - "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", - "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", - "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", - "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", - "type": "Organization", - "site_admin": false - }, - "repo": { - "id": 893522, - "name": "node-serialport", - "full_name": "EmergingTechnologyAdvisors/node-serialport", - "owner": { - "login": "EmergingTechnologyAdvisors", - "id": 8947774, - "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/EmergingTechnologyAdvisors", - "html_url": "https://github.com/EmergingTechnologyAdvisors", - "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", - "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", - "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", - "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", - "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", - "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", - "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", - "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", - "type": "Organization", - "site_admin": false - }, - "private": false, - "html_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", - "description": "Node.js package to access serial ports for reading and writing. Welcome your robotic JavaScript overlords. Better yet, program them!", - "fork": false, - "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport", - "forks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/forks", - "keys_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/keys{/key_id}", - "collaborators_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/collaborators{/collaborator}", - "teams_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/teams", - "hooks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/hooks", - "issue_events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/events{/number}", - "events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/events", - "assignees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/assignees{/user}", - "branches_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/branches{/branch}", - "tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/tags", - "blobs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/blobs{/sha}", - "git_tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/tags{/sha}", - "git_refs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/refs{/sha}", - "trees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/trees{/sha}", - "statuses_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/{sha}", - "languages_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/languages", - "stargazers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/stargazers", - "contributors_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contributors", - "subscribers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscribers", - "subscription_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscription", - "commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/commits{/sha}", - "git_commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/commits{/sha}", - "comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/comments{/number}", - "issue_comment_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/comments{/number}", - "contents_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contents/{+path}", - "compare_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/compare/{base}...{head}", - "merges_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/merges", - "archive_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/{archive_format}{/ref}", - "downloads_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/downloads", - "issues_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues{/number}", - "pulls_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls{/number}", - "milestones_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/milestones{/number}", - "notifications_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/notifications{?since,all,participating}", - "labels_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/labels{/name}", - "releases_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/releases{/id}", - "deployments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/deployments", - "created_at": "2010-09-07T12:24:28Z", - "updated_at": "2017-07-14T16:30:58Z", - "pushed_at": "2017-07-15T17:06:45Z", - "git_url": "git://github.com/EmergingTechnologyAdvisors/node-serialport.git", - "ssh_url": "git@github.com:EmergingTechnologyAdvisors/node-serialport.git", - "clone_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport.git", - "svn_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", - "homepage": "", - "size": 1914, - "stargazers_count": 2829, - "watchers_count": 2829, - "language": "JavaScript", - "has_issues": true, - "has_projects": true, - "has_downloads": true, - "has_wiki": false, - "has_pages": true, - "forks_count": 601, - "mirror_url": null, - "open_issues_count": 30, - "forks": 601, - "open_issues": 30, - "watchers": 2829, - "default_branch": "master" - } - }, - "_links": { - "self": { - "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235" - }, - "html": { - "href": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235" - }, - "issue": { - "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235" - }, - "comments": { - "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235/comments" - }, - "review_comments": { - "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/comments" - }, - "review_comment": { - "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/comments{/number}" - }, - "commits": { - "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/commits" - }, - "statuses": { - "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/e57b3d685f6497ebe8669ce8b05894bacd895177" - } - }, - "merged": true, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": { - "login": "reconbot", - "id": 25966, - "avatar_url": "https://avatars6.githubusercontent.com/u/25966?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/reconbot", - "html_url": "https://github.com/reconbot", - "followers_url": "https://api.github.com/users/reconbot/followers", - "following_url": "https://api.github.com/users/reconbot/following{/other_user}", - "gists_url": "https://api.github.com/users/reconbot/gists{/gist_id}", - "starred_url": "https://api.github.com/users/reconbot/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/reconbot/subscriptions", - "organizations_url": "https://api.github.com/users/reconbot/orgs", - "repos_url": "https://api.github.com/users/reconbot/repos", - "events_url": "https://api.github.com/users/reconbot/events{/privacy}", - "received_events_url": "https://api.github.com/users/reconbot/received_events", - "type": "User", - "site_admin": false - }, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 24, - "deletions": 14, - "changed_files": 2 - } - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z", - "org": { - "id": 8947774, - "login": "EmergingTechnologyAdvisors", - "gravatar_id": "", - "url": "https://api.github.com/orgs/EmergingTechnologyAdvisors", - "avatar_url": "https://avatars.githubusercontent.com/u/8947774?" - } - }, - { - "id": "6263117447", - "type": "PushEvent", - "actor": { - "id": 11887843, - "login": "trimox", - "display_login": "trimox", - "gravatar_id": "", - "url": "https://api.github.com/users/trimox", - "avatar_url": "https://avatars.githubusercontent.com/u/11887843?" - }, - "repo": { - "id": 88184430, - "name": "trimox/angular-mdc-web", - "url": "https://api.github.com/repos/trimox/angular-mdc-web" - }, - "payload": { - "push_id": 1861573792, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "59de0a8bfb229e7e72a1960132fdf24f0a770a08", - "before": "27327b3a3cb4e58ddb1b1188cb0f04092d850106", - "commits": [{ - "sha": "59de0a8bfb229e7e72a1960132fdf24f0a770a08", - "author": { - "email": "trimoxal@gmail.com", - "name": "Dominic Carretto" - }, - "message": "fix(snackbar): Fix actionHandler still required if actionText is empty", - "distinct": true, - "url": "https://api.github.com/repos/trimox/angular-mdc-web/commits/59de0a8bfb229e7e72a1960132fdf24f0a770a08" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:46Z" - }, - { - "id": "6263117445", - "type": "WatchEvent", - "actor": { - "id": 1006434, - "login": "enorrmann", - "display_login": "enorrmann", - "gravatar_id": "", - "url": "https://api.github.com/users/enorrmann", - "avatar_url": "https://avatars.githubusercontent.com/u/1006434?" - }, - "repo": { - "id": 14699489, - "name": "walmik/scribbletune", - "url": "https://api.github.com/repos/walmik/scribbletune" - }, - "payload": { - "action": "started" - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117444", - "type": "PushEvent", - "actor": { - "id": 24412103, - "login": "james341", - "display_login": "james341", - "gravatar_id": "", - "url": "https://api.github.com/users/james341", - "avatar_url": "https://avatars.githubusercontent.com/u/24412103?" - }, - "repo": { - "id": 96979484, - "name": "james341/loading-yan-rp", - "url": "https://api.github.com/repos/james341/loading-yan-rp" - }, - "payload": { - "push_id": 1861573791, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "16bb35eb4a43d916a40155996c9d7dfadb007573", - "before": "ad4b96a5b924783e42d1d0cbf0fd1b5cba3cbd2f", - "commits": [{ - "sha": "16bb35eb4a43d916a40155996c9d7dfadb007573", - "author": { - "email": "taine049@gmail.com", - "name": "james341" - }, - "message": "Add files via upload", - "distinct": true, - "url": "https://api.github.com/repos/james341/loading-yan-rp/commits/16bb35eb4a43d916a40155996c9d7dfadb007573" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117441", - "type": "PushEvent", - "actor": { - "id": 4676211, - "login": "kanke", - "display_login": "kanke", - "gravatar_id": "", - "url": "https://api.github.com/users/kanke", - "avatar_url": "https://avatars.githubusercontent.com/u/4676211?" - }, - "repo": { - "id": 97262451, - "name": "kanke/RedisServerClone", - "url": "https://api.github.com/repos/kanke/RedisServerClone" - }, - "payload": { - "push_id": 1861573790, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "e6312819f0acdc40008b06ae7a2c6c211c2f1db0", - "before": "f9a4fe7e866181c74fbc9352310fbc6c539d2aff", - "commits": [{ - "sha": "e6312819f0acdc40008b06ae7a2c6c211c2f1db0", - "author": { - "email": "sugarkanke@yahoo.com", - "name": "Kanke" - }, - "message": "Adding gitignore and readme.md content. Code cleanup.", - "distinct": true, - "url": "https://api.github.com/repos/kanke/RedisServerClone/commits/e6312819f0acdc40008b06ae7a2c6c211c2f1db0" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117440", - "type": "PushEvent", - "actor": { - "id": 16622965, - "login": "jainhitesh9998", - "display_login": "jainhitesh9998", - "gravatar_id": "", - "url": "https://api.github.com/users/jainhitesh9998", - "avatar_url": "https://avatars.githubusercontent.com/u/16622965?" - }, - "repo": { - "id": 94244445, - "name": "jainhitesh9998/WebDevelopment", - "url": "https://api.github.com/repos/jainhitesh9998/WebDevelopment" - }, - "payload": { - "push_id": 1861573789, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "9e3c3f5f437fbc1f21a30f19f764787b86a393be", - "before": "d69d496b80a5806406f2313d67e63f3adf61b97e", - "commits": [{ - "sha": "9e3c3f5f437fbc1f21a30f19f764787b86a393be", - "author": { - "email": "jainhitesh9998@gmail.com", - "name": "Hitesh C" - }, - "message": "added sounds for the clone", - "distinct": true, - "url": "https://api.github.com/repos/jainhitesh9998/WebDevelopment/commits/9e3c3f5f437fbc1f21a30f19f764787b86a393be" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117437", - "type": "PushEvent", - "actor": { - "id": 1491646, - "login": "MikroAcse", - "display_login": "MikroAcse", - "gravatar_id": "", - "url": "https://api.github.com/users/MikroAcse", - "avatar_url": "https://avatars.githubusercontent.com/u/1491646?" - }, - "repo": { - "id": 96892535, - "name": "MikroAcse/VariousTelegramBots", - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots" - }, - "payload": { - "push_id": 1861573788, - "size": 11, - "distinct_size": 11, - "ref": "refs/heads/dev", - "head": "7ef25bf6aad45c9da53a2d5918e553c68cd69dd4", - "before": "931cef7db8ec69cc951fe8a5ecc2b909397e29a4", - "commits": [{ - "sha": "88b9e4e53f62ff7c9597f66d9e45a0a9be5fe1ca", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "upgrade Node.js version", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/88b9e4e53f62ff7c9597f66d9e45a0a9be5fe1ca" - }, - { - "sha": "d5b91bac58a8c3b88ddd9634578cb3beebb31015", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Update Node js version", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/d5b91bac58a8c3b88ddd9634578cb3beebb31015" - }, - { - "sha": "37cd86961e36e64c8ccd7873bbccc200b920d308", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Fix", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/37cd86961e36e64c8ccd7873bbccc200b920d308" - }, - { - "sha": "471451fd46b9bed62eef062553f480e788c24a3c", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Merge branch 'master' into dev\n\n# Conflicts:\n#\tapp.js", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/471451fd46b9bed62eef062553f480e788c24a3c" - }, - { - "sha": "8f5be591fae47f1ff051f992176faeed8fe3c2d7", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Removed unnecessary dependency and updated README.md", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/8f5be591fae47f1ff051f992176faeed8fe3c2d7" - }, - { - "sha": "d239750fbb26f13daf50a14e1c4a23375df9c5d9", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Update README", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/d239750fbb26f13daf50a14e1c4a23375df9c5d9" - }, - { - "sha": "94adaefc2b4107db89cdbc045a6a106724f12a2d", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Fix in readme", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/94adaefc2b4107db89cdbc045a6a106724f12a2d" - }, - { - "sha": "da8009c4da182c036efbc7a8e9d9353d1282d5ed", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Added version to readme", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/da8009c4da182c036efbc7a8e9d9353d1282d5ed" - }, - { - "sha": "1590092c64e774633040419b69d60d98197ddbde", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Removed requirement of deleted dependency", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/1590092c64e774633040419b69d60d98197ddbde" - }, - { - "sha": "1986905b1d32654a20916fafc60c7484ff85841a", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Yes or no in ChooseBot, slight changes in QuoteBot regexp", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/1986905b1d32654a20916fafc60c7484ff85841a" - }, - { - "sha": "7ef25bf6aad45c9da53a2d5918e553c68cd69dd4", - "author": { - "email": "mike.kroace@gmail.com", - "name": "Vitaly Rudenko" - }, - "message": "Merge commit '1986905b1d32654a20916fafc60c7484ff85841a' into dev", - "distinct": true, - "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/7ef25bf6aad45c9da53a2d5918e553c68cd69dd4" - } - ] - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117435", - "type": "PushEvent", - "actor": { - "id": 12949454, - "login": "jarifibrahim", - "display_login": "jarifibrahim", - "gravatar_id": "", - "url": "https://api.github.com/users/jarifibrahim", - "avatar_url": "https://avatars.githubusercontent.com/u/12949454?" - }, - "repo": { - "id": 93039796, - "name": "jarifibrahim/OpenSourceHelpCommunity.github.io", - "url": "https://api.github.com/repos/jarifibrahim/OpenSourceHelpCommunity.github.io" - }, - "payload": { - "push_id": 1861573787, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/issue-4", - "head": "4b7341d9b7bb95f5f0e1d50831a9c978fc4fceb4", - "before": "57c0a65ee93de1955ad5691585a51c358188f311", - "commits": [{ - "sha": "4b7341d9b7bb95f5f0e1d50831a9c978fc4fceb4", - "author": { - "email": "jarifibrahim@gmail.com", - "name": "Ibrahim Jarif" - }, - "message": "Add travs.yml", - "distinct": true, - "url": "https://api.github.com/repos/jarifibrahim/OpenSourceHelpCommunity.github.io/commits/4b7341d9b7bb95f5f0e1d50831a9c978fc4fceb4" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117430", - "type": "IssueCommentEvent", - "actor": { - "id": 849609, - "login": "wrrn", - "display_login": "wrrn", - "gravatar_id": "", - "url": "https://api.github.com/users/wrrn", - "avatar_url": "https://avatars.githubusercontent.com/u/849609?" - }, - "repo": { - "id": 23096959, - "name": "golang/go", - "url": "https://api.github.com/repos/golang/go" - }, - "payload": { - "action": "created", - "issue": { - "url": "https://api.github.com/repos/golang/go/issues/21017", - "repository_url": "https://api.github.com/repos/golang/go", - "labels_url": "https://api.github.com/repos/golang/go/issues/21017/labels{/name}", - "comments_url": "https://api.github.com/repos/golang/go/issues/21017/comments", - "events_url": "https://api.github.com/repos/golang/go/issues/21017/events", - "html_url": "https://github.com/golang/go/issues/21017", - "id": 243177572, - "number": 21017, - "title": "Gophercon: Contributor Workshop Registration", - "user": { - "login": "jessfraz", - "id": 1445228, - "avatar_url": "https://avatars6.githubusercontent.com/u/1445228?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/jessfraz", - "html_url": "https://github.com/jessfraz", - "followers_url": "https://api.github.com/users/jessfraz/followers", - "following_url": "https://api.github.com/users/jessfraz/following{/other_user}", - "gists_url": "https://api.github.com/users/jessfraz/gists{/gist_id}", - "starred_url": "https://api.github.com/users/jessfraz/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/jessfraz/subscriptions", - "organizations_url": "https://api.github.com/users/jessfraz/orgs", - "repos_url": "https://api.github.com/users/jessfraz/repos", - "events_url": "https://api.github.com/users/jessfraz/events{/privacy}", - "received_events_url": "https://api.github.com/users/jessfraz/received_events", - "type": "User", - "site_admin": false - }, - "labels": [{ - "id": 150880243, - "url": "https://api.github.com/repos/golang/go/labels/HelpWanted", - "name": "HelpWanted", - "color": "fbca04", - "default": false - }], - "state": "open", - "locked": false, - "assignee": null, - "assignees": [ - - ], - "milestone": { - "url": "https://api.github.com/repos/golang/go/milestones/22", - "html_url": "https://github.com/golang/go/milestone/22", - "labels_url": "https://api.github.com/repos/golang/go/milestones/22/labels", - "id": 1067491, - "number": 22, - "title": "Unreleased", - "description": "Issues that do not affect released Go code and binaries.\r\n", - "creator": { - "login": "rsc", - "id": 104030, - "avatar_url": "https://avatars5.githubusercontent.com/u/104030?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/rsc", - "html_url": "https://github.com/rsc", - "followers_url": "https://api.github.com/users/rsc/followers", - "following_url": "https://api.github.com/users/rsc/following{/other_user}", - "gists_url": "https://api.github.com/users/rsc/gists{/gist_id}", - "starred_url": "https://api.github.com/users/rsc/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/rsc/subscriptions", - "organizations_url": "https://api.github.com/users/rsc/orgs", - "repos_url": "https://api.github.com/users/rsc/repos", - "events_url": "https://api.github.com/users/rsc/events{/privacy}", - "received_events_url": "https://api.github.com/users/rsc/received_events", - "type": "User", - "site_admin": false - }, - "open_issues": 707, - "closed_issues": 918, - "state": "open", - "created_at": "2015-04-14T18:48:22Z", - "updated_at": "2017-07-15T17:06:04Z", - "due_on": "2099-12-31T08:00:00Z", - "closed_at": null - }, - "comments": 14, - "created_at": "2017-07-15T14:13:29Z", - "updated_at": "2017-07-15T17:06:43Z", - "closed_at": null, - "body": "Please do not comment here until the Contributor Workshop begins.\r\n\r\nDuring the workshop leave a comment with your Gerritt profile ID here." - }, - "comment": { - "url": "https://api.github.com/repos/golang/go/issues/comments/315547934", - "html_url": "https://github.com/golang/go/issues/21017#issuecomment-315547934", - "issue_url": "https://api.github.com/repos/golang/go/issues/21017", - "id": 315547934, - "user": { - "login": "wrrn", - "id": 849609, - "avatar_url": "https://avatars7.githubusercontent.com/u/849609?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/wrrn", - "html_url": "https://github.com/wrrn", - "followers_url": "https://api.github.com/users/wrrn/followers", - "following_url": "https://api.github.com/users/wrrn/following{/other_user}", - "gists_url": "https://api.github.com/users/wrrn/gists{/gist_id}", - "starred_url": "https://api.github.com/users/wrrn/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/wrrn/subscriptions", - "organizations_url": "https://api.github.com/users/wrrn/orgs", - "repos_url": "https://api.github.com/users/wrrn/repos", - "events_url": "https://api.github.com/users/wrrn/events{/privacy}", - "received_events_url": "https://api.github.com/users/wrrn/received_events", - "type": "User", - "site_admin": false - }, - "created_at": "2017-07-15T17:06:43Z", - "updated_at": "2017-07-15T17:06:43Z", - "body": "22590" - } - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z", - "org": { - "id": 4314092, - "login": "golang", - "gravatar_id": "", - "url": "https://api.github.com/orgs/golang", - "avatar_url": "https://avatars.githubusercontent.com/u/4314092?" - } - }, - { - "id": "6263117428", - "type": "PushEvent", - "actor": { - "id": 6938676, - "login": "Ordinastie", - "display_login": "Ordinastie", - "gravatar_id": "", - "url": "https://api.github.com/users/Ordinastie", - "avatar_url": "https://avatars.githubusercontent.com/u/6938676?" - }, - "repo": { - "id": 17756561, - "name": "Ordinastie/MalisisDoors", - "url": "https://api.github.com/repos/Ordinastie/MalisisDoors" - }, - "payload": { - "push_id": 1861573783, - "size": 2, - "distinct_size": 2, - "ref": "refs/heads/1.12", - "head": "07334b1700ec9cd173c7560f293b7dd10dc24fd9", - "before": "ee8e1058833056afdcac559c22518b3706b3657f", - "commits": [{ - "sha": "52080012d79ae0320392379b5d054f3e17ec1b98", - "author": { - "email": "ordinastie@hotmail.com", - "name": "Ordinastie" - }, - "message": "Fixed getRegistryType()", - "distinct": true, - "url": "https://api.github.com/repos/Ordinastie/MalisisDoors/commits/52080012d79ae0320392379b5d054f3e17ec1b98" - }, - { - "sha": "07334b1700ec9cd173c7560f293b7dd10dc24fd9", - "author": { - "email": "ordinastie@hotmail.com", - "name": "Ordinastie" - }, - "message": "Updated forgegradle and curseforge version", - "distinct": true, - "url": "https://api.github.com/repos/Ordinastie/MalisisDoors/commits/07334b1700ec9cd173c7560f293b7dd10dc24fd9" - } - ] - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117427", - "type": "DeleteEvent", - "actor": { - "id": 227909, - "login": "amcdnl", - "display_login": "amcdnl", - "gravatar_id": "", - "url": "https://api.github.com/users/amcdnl", - "avatar_url": "https://avatars.githubusercontent.com/u/227909?" - }, - "repo": { - "id": 94944874, - "name": "amcdnl/material2", - "url": "https://api.github.com/repos/amcdnl/material2" - }, - "payload": { - "ref": "autocomplete-demos", - "ref_type": "branch", - "pusher_type": "user" - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - }, - { - "id": "6263117426", - "type": "PushEvent", - "actor": { - "id": 16347325, - "login": "zxui", - "display_login": "zxui", - "gravatar_id": "", - "url": "https://api.github.com/users/zxui", - "avatar_url": "https://avatars.githubusercontent.com/u/16347325?" - }, - "repo": { - "id": 88623154, - "name": "zxui/auto-admin", - "url": "https://api.github.com/repos/zxui/auto-admin" - }, - "payload": { - "push_id": 1861573782, - "size": 1, - "distinct_size": 1, - "ref": "refs/heads/master", - "head": "70d47755fde8a5c4cfde101ba65caa6c1d6fcdb2", - "before": "f673e6b191197827bddb31bcffea61611e8a50b0", - "commits": [{ - "sha": "70d47755fde8a5c4cfde101ba65caa6c1d6fcdb2", - "author": { - "email": "zxshen@qq.com", - "name": "zxui" - }, - "message": "update", - "distinct": true, - "url": "https://api.github.com/repos/zxui/auto-admin/commits/70d47755fde8a5c4cfde101ba65caa6c1d6fcdb2" - }] - }, - "public": true, - "created_at": "2017-07-15T17:06:45Z" - } - ] +[ + { + "id": "6263117491", + "type": "PushEvent", + "actor": { + "id": 12358972, + "login": "CodePipeline-Test", + "display_login": "CodePipeline-Test", + "gravatar_id": "", + "url": "https://api.github.com/users/CodePipeline-Test", + "avatar_url": "https://avatars.githubusercontent.com/u/12358972?" + }, + "repo": { + "id": 63971386, + "name": "CodePipeline-Test/feature-tests", + "url": "https://api.github.com/repos/CodePipeline-Test/feature-tests" + }, + "payload": { + "push_id": 1861573815, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/job-worker-features-V5zkpTEUgBlA4TOEJrWq", + "head": "f283b1955dd88fe65210c842e63408d5ad30d322", + "before": "873d322eb50db0068ae3d0ea2e79cee345e31c93", + "commits": [ + { + "sha": "f283b1955dd88fe65210c842e63408d5ad30d322", + "author": { + "email": "CodePipeline-Test@users.noreply.github.com", + "name": "CodePipeline-Test" + }, + "message": "Test commit", + "distinct": true, + "url": "https://api.github.com/repos/CodePipeline-Test/feature-tests/commits/f283b1955dd88fe65210c842e63408d5ad30d322" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:47Z" + }, + { + "id": "6263117489", + "type": "PushEvent", + "actor": { + "id": 16156445, + "login": "JonnyPickard", + "display_login": "JonnyPickard", + "gravatar_id": "", + "url": "https://api.github.com/users/JonnyPickard", + "avatar_url": "https://avatars.githubusercontent.com/u/16156445?" + }, + "repo": { + "id": 97318059, + "name": "JonnyPickard/albums-react-native", + "url": "https://api.github.com/repos/JonnyPickard/albums-react-native" + }, + "payload": { + "push_id": 1861573814, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "a11c7aedf4f1800357864302fe08fc277e9e8652", + "before": "d33e7adbb46926d1d4030d0c855b245062f1d9b5", + "commits": [ + { + "sha": "a11c7aedf4f1800357864302fe08fc277e9e8652", + "author": { + "email": "jonathandpickard@gmail.com", + "name": "Jonny Pickard" + }, + "message": "Add basic server to send JSON", + "distinct": true, + "url": "https://api.github.com/repos/JonnyPickard/albums-react-native/commits/a11c7aedf4f1800357864302fe08fc277e9e8652" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:47Z" + }, + { + "id": "6263117487", + "type": "IssueCommentEvent", + "actor": { + "id": 4236651, + "login": "0x53A", + "display_login": "0x53A", + "gravatar_id": "", + "url": "https://api.github.com/users/0x53A", + "avatar_url": "https://avatars.githubusercontent.com/u/4236651?" + }, + "repo": { + "id": 29048891, + "name": "Microsoft/visualfsharp", + "url": "https://api.github.com/repos/Microsoft/visualfsharp" + }, + "payload": { + "action": "created", + "issue": { + "url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335", + "repository_url": "https://api.github.com/repos/Microsoft/visualfsharp", + "labels_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335/labels{/name}", + "comments_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335/comments", + "events_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335/events", + "html_url": "https://github.com/Microsoft/visualfsharp/issues/3335", + "id": 243089775, + "number": 3335, + "title": "[15.3 pre] loading in VS / publish fails if FSharp.Compiler.Tools is imported", + "user": { + "login": "0x53A", + "id": 4236651, + "avatar_url": "https://avatars7.githubusercontent.com/u/4236651?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/0x53A", + "html_url": "https://github.com/0x53A", + "followers_url": "https://api.github.com/users/0x53A/followers", + "following_url": "https://api.github.com/users/0x53A/following{/other_user}", + "gists_url": "https://api.github.com/users/0x53A/gists{/gist_id}", + "starred_url": "https://api.github.com/users/0x53A/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/0x53A/subscriptions", + "organizations_url": "https://api.github.com/users/0x53A/orgs", + "repos_url": "https://api.github.com/users/0x53A/repos", + "events_url": "https://api.github.com/users/0x53A/events{/privacy}", + "received_events_url": "https://api.github.com/users/0x53A/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 308803045, + "url": "https://api.github.com/repos/Microsoft/visualfsharp/labels/Area-CoreCLR", + "name": "Area-CoreCLR", + "color": "5319e7", + "default": false + } + ], + "state": "closed", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": { + "url": "https://api.github.com/repos/Microsoft/visualfsharp/milestones/9", + "html_url": "https://github.com/Microsoft/visualfsharp/milestone/9", + "labels_url": "https://api.github.com/repos/Microsoft/visualfsharp/milestones/9/labels", + "id": 2233574, + "number": 9, + "title": "VS 2017 Updates", + "description": "This milestone is for any bug, new feature, or improvement which makes it into a later VS 2017 update.", + "creator": { + "login": "cartermp", + "id": 6309070, + "avatar_url": "https://avatars4.githubusercontent.com/u/6309070?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/cartermp", + "html_url": "https://github.com/cartermp", + "followers_url": "https://api.github.com/users/cartermp/followers", + "following_url": "https://api.github.com/users/cartermp/following{/other_user}", + "gists_url": "https://api.github.com/users/cartermp/gists{/gist_id}", + "starred_url": "https://api.github.com/users/cartermp/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/cartermp/subscriptions", + "organizations_url": "https://api.github.com/users/cartermp/orgs", + "repos_url": "https://api.github.com/users/cartermp/repos", + "events_url": "https://api.github.com/users/cartermp/events{/privacy}", + "received_events_url": "https://api.github.com/users/cartermp/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 55, + "closed_issues": 158, + "state": "open", + "created_at": "2017-01-06T17:42:02Z", + "updated_at": "2017-07-15T00:13:34Z", + "due_on": null, + "closed_at": null + }, + "comments": 29, + "created_at": "2017-07-14T19:28:04Z", + "updated_at": "2017-07-15T17:06:46Z", + "closed_at": "2017-07-15T00:13:33Z", + "body": "\r\nEdit2: everything works, thanks @KevinRansom \r\n\r\n_Edited_\r\n\r\nI have tried to test if / how a project using paket works in the new world of ``dotnet 2``, comparing C#, F#, and the previous F# sdk (FSharp.NET.Sdk). I have also tested if using F# without paket works.\r\n\r\nHere are four branches, one for each test: https://github.com/0x53A/dotnet-tests.\r\n\r\nResults:\r\n\r\n* paket works with C# and ``Microsoft.NET.Sdk``: https://github.com/0x53A/dotnet-tests/tree/csharp+paket\r\n* paket works with F# when using the 1.x sdk (``FSharp.NET.Sdk``): https://github.com/0x53A/dotnet-tests/tree/fsharp+paket+FSharp.NET.Sdk\r\n* paket ~does NOT~ does work with F# and ``Microsoft.NET.Sdk``: https://github.com/0x53A/dotnet-tests/tree/fsharp+paket\r\n* using F# with ``Microsoft.NET.Sdk`` and nuget does work: https://github.com/0x53A/dotnet-tests/tree/fsharp+nuget\r\n\r\nThe paket version I have tested this with is ``5.6.12``.\r\n\r\nIt is kind of funny that C# seems to work flawlessly with paket." + }, + "comment": { + "url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/comments/315547940", + "html_url": "https://github.com/Microsoft/visualfsharp/issues/3335#issuecomment-315547940", + "issue_url": "https://api.github.com/repos/Microsoft/visualfsharp/issues/3335", + "id": 315547940, + "user": { + "login": "0x53A", + "id": 4236651, + "avatar_url": "https://avatars7.githubusercontent.com/u/4236651?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/0x53A", + "html_url": "https://github.com/0x53A", + "followers_url": "https://api.github.com/users/0x53A/followers", + "following_url": "https://api.github.com/users/0x53A/following{/other_user}", + "gists_url": "https://api.github.com/users/0x53A/gists{/gist_id}", + "starred_url": "https://api.github.com/users/0x53A/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/0x53A/subscriptions", + "organizations_url": "https://api.github.com/users/0x53A/orgs", + "repos_url": "https://api.github.com/users/0x53A/repos", + "events_url": "https://api.github.com/users/0x53A/events{/privacy}", + "received_events_url": "https://api.github.com/users/0x53A/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2017-07-15T17:06:46Z", + "updated_at": "2017-07-15T17:06:46Z", + "body": "3) DisableImplicitFSharpCoreReference and paket\r\n\r\npaket.dependencies:\r\n\r\n```nuget FSharp.Core 4.0.0.1```\r\n\r\n```Xml\r\n\r\n \r\n net461\r\n true\r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n\r\n=>\r\n\r\n```\r\nC:\\source\\dotnet-tests>dotnet publish\r\nMicrosoft (R) Build Engine version 15.3.406.54721 for .NET Core\r\nCopyright (C) Microsoft Corporation. All rights reserved.\r\n\r\nC:\\source\\dotnet-tests\\Library.fs(7,17): error FS0039: The value, namespace, type or module 'Result' is not defined. [C:\\source\\dotnet-tests\\paket-fsharp-test.fsproj]\r\nC:\\source\\dotnet-tests\\Library.fs(8,42): error FS0039: The pattern discriminator 'Ok' is not defined. [C:\\source\\dotnet-tests\\paket-fsharp-test.fsproj]\r\n```\r\n\r\nwhich is good.\r\n\r\n-----------------\r\n\r\nSo it looks like both properties work as expected. It seems that in __2)__ the compiler automagically referenced some FSharp.Core, because none was explicitly referenced." + } + }, + "public": true, + "created_at": "2017-07-15T17:06:47Z", + "org": { + "id": 6154722, + "login": "Microsoft", + "gravatar_id": "", + "url": "https://api.github.com/orgs/Microsoft", + "avatar_url": "https://avatars.githubusercontent.com/u/6154722?" + } + }, + { + "id": "6263117486", + "type": "PushEvent", + "actor": { + "id": 982267, + "login": "gxela", + "display_login": "gxela", + "gravatar_id": "", + "url": "https://api.github.com/users/gxela", + "avatar_url": "https://avatars.githubusercontent.com/u/982267?" + }, + "repo": { + "id": 97197951, + "name": "AudioBible/AudioBible.life", + "url": "https://api.github.com/repos/AudioBible/AudioBible.life" + }, + "payload": { + "push_id": 1861573811, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "31e079597959be78850e06c623383d522f8fe283", + "before": "11d32ac0eb7051ddc7da05dab183f10ed861fa61", + "commits": [ + { + "sha": "31e079597959be78850e06c623383d522f8fe283", + "author": { + "email": "alex@goretoy.com", + "name": "Alex Goretoy" + }, + "message": "update", + "distinct": true, + "url": "https://api.github.com/repos/AudioBible/AudioBible.life/commits/31e079597959be78850e06c623383d522f8fe283" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:47Z", + "org": { + "id": 29329308, + "login": "AudioBible", + "gravatar_id": "", + "url": "https://api.github.com/orgs/AudioBible", + "avatar_url": "https://avatars.githubusercontent.com/u/29329308?" + } + }, + { + "id": "6263117481", + "type": "CreateEvent", + "actor": { + "id": 998519, + "login": "martinstabe", + "display_login": "martinstabe", + "gravatar_id": "", + "url": "https://api.github.com/users/martinstabe", + "avatar_url": "https://avatars.githubusercontent.com/u/998519?" + }, + "repo": { + "id": 90621389, + "name": "ft-interactive/archive", + "url": "https://api.github.com/repos/ft-interactive/archive" + }, + "payload": { + "ref": "personal-data", + "ref_type": "branch", + "master_branch": "master", + "description": "Refactored versions of a few older FT interactive stories", + "pusher_type": "user" + }, + "public": true, + "created_at": "2017-07-15T17:06:47Z", + "org": { + "id": 2511089, + "login": "ft-interactive", + "gravatar_id": "", + "url": "https://api.github.com/orgs/ft-interactive", + "avatar_url": "https://avatars.githubusercontent.com/u/2511089?" + } + }, + { + "id": "6263117480", + "type": "PushEvent", + "actor": { + "id": 30200303, + "login": "musikdusche", + "display_login": "musikdusche", + "gravatar_id": "", + "url": "https://api.github.com/users/musikdusche", + "avatar_url": "https://avatars.githubusercontent.com/u/30200303?" + }, + "repo": { + "id": 97330240, + "name": "musikdusche/hello-world", + "url": "https://api.github.com/repos/musikdusche/hello-world" + }, + "payload": { + "push_id": 1861573809, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/readmeworks", + "head": "e09f4ef810382578be4ba49bcc351c94ac8b15f9", + "before": "10f052d3f22eaad13302b5e0e6d1a4af77a73f91", + "commits": [ + { + "sha": "e09f4ef810382578be4ba49bcc351c94ac8b15f9", + "author": { + "email": "f.toens@gmx.de", + "name": "musikdusche" + }, + "message": "Update README.md\n\ntrying out markdown syntaxes", + "distinct": true, + "url": "https://api.github.com/repos/musikdusche/hello-world/commits/e09f4ef810382578be4ba49bcc351c94ac8b15f9" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:47Z" + }, + { + "id": "6263117478", + "type": "PushEvent", + "actor": { + "id": 4712642, + "login": "neu-rah", + "display_login": "neu-rah", + "gravatar_id": "", + "url": "https://api.github.com/users/neu-rah", + "avatar_url": "https://avatars.githubusercontent.com/u/4712642?" + }, + "repo": { + "id": 23024191, + "name": "neu-rah/ArduinoMenu", + "url": "https://api.github.com/repos/neu-rah/ArduinoMenu" + }, + "payload": { + "push_id": 1861573808, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "1557e3155279ca19e35048f8a6758189cbb2231a", + "before": "fb1b8c70b324bf73231728a708fe496991c51607", + "commits": [ + { + "sha": "1557e3155279ca19e35048f8a6758189cbb2231a", + "author": { + "email": "ruihfazevedo@gmail.com", + "name": "Rui Azevedo" + }, + "message": "remove pin collision between encoder and serial on I2C example as noted by Paul Gaertner", + "distinct": true, + "url": "https://api.github.com/repos/neu-rah/ArduinoMenu/commits/1557e3155279ca19e35048f8a6758189cbb2231a" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:47Z" + }, + { + "id": "6263117476", + "type": "PushEvent", + "actor": { + "id": 22308572, + "login": "zfang399", + "display_login": "zfang399", + "gravatar_id": "", + "url": "https://api.github.com/users/zfang399", + "avatar_url": "https://avatars.githubusercontent.com/u/22308572?" + }, + "repo": { + "id": 93472978, + "name": "zfang399/LeetCode-Problems", + "url": "https://api.github.com/repos/zfang399/LeetCode-Problems" + }, + "payload": { + "push_id": 1861573807, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "dffd54fc9872b0a14ae7b3089c541db439c77dc6", + "before": "31643c5f628a91714dabf3c0472d6b3b6f2d75f9", + "commits": [ + { + "sha": "dffd54fc9872b0a14ae7b3089c541db439c77dc6", + "author": { + "email": "zfang@nd.edu", + "name": "Zhaoyuan Fang" + }, + "message": "Reverse Linked List II", + "distinct": true, + "url": "https://api.github.com/repos/zfang399/LeetCode-Problems/commits/dffd54fc9872b0a14ae7b3089c541db439c77dc6" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z" + }, + { + "id": "6263117475", + "type": "PushEvent", + "actor": { + "id": 4750766, + "login": "rohintangirala", + "display_login": "rohintangirala", + "gravatar_id": "", + "url": "https://api.github.com/users/rohintangirala", + "avatar_url": "https://avatars.githubusercontent.com/u/4750766?" + }, + "repo": { + "id": 97284340, + "name": "Twenty-App/Twenty-App.github.io", + "url": "https://api.github.com/repos/Twenty-App/Twenty-App.github.io" + }, + "payload": { + "push_id": 1861573806, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "90effa1defcc57fbb19d118a3cf773e200542333", + "before": "a3a94db8f23bec183df701cc6f27b761be8f6250", + "commits": [ + { + "sha": "90effa1defcc57fbb19d118a3cf773e200542333", + "author": { + "email": "rohinkt@gmail.com", + "name": "Rohin Tangirala" + }, + "message": "Set theme jekyll-theme-tactile", + "distinct": true, + "url": "https://api.github.com/repos/Twenty-App/Twenty-App.github.io/commits/90effa1defcc57fbb19d118a3cf773e200542333" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z", + "org": { + "id": 30188091, + "login": "Twenty-App", + "gravatar_id": "", + "url": "https://api.github.com/orgs/Twenty-App", + "avatar_url": "https://avatars.githubusercontent.com/u/30188091?" + } + }, + { + "id": "6263117473", + "type": "PushEvent", + "actor": { + "id": 8517910, + "login": "LombiqBot", + "display_login": "LombiqBot", + "gravatar_id": "", + "url": "https://api.github.com/users/LombiqBot", + "avatar_url": "https://avatars.githubusercontent.com/u/8517910?" + }, + "repo": { + "id": 46594739, + "name": "Lombiq/Associativy-Taxonomies-Adapter", + "url": "https://api.github.com/repos/Lombiq/Associativy-Taxonomies-Adapter" + }, + "payload": { + "push_id": 1861573805, + "size": 0, + "distinct_size": 0, + "ref": "refs/heads/orchard-upgrade-1.10", + "head": "e1d77dd00dfdc65d5d84b1712be94e609273c838", + "before": "e1d77dd00dfdc65d5d84b1712be94e609273c838", + "commits": [] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z", + "org": { + "id": 8158177, + "login": "Lombiq", + "gravatar_id": "", + "url": "https://api.github.com/orgs/Lombiq", + "avatar_url": "https://avatars.githubusercontent.com/u/8158177?" + } + }, + { + "id": "6263117472", + "type": "PushEvent", + "actor": { + "id": 25966, + "login": "reconbot", + "display_login": "reconbot", + "gravatar_id": "", + "url": "https://api.github.com/users/reconbot", + "avatar_url": "https://avatars.githubusercontent.com/u/25966?" + }, + "repo": { + "id": 893522, + "name": "EmergingTechnologyAdvisors/node-serialport", + "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport" + }, + "payload": { + "push_id": 1861573804, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a", + "before": "2361fa599a16a10ad07ffe863fe00bb2bc75d29a", + "commits": [ + { + "sha": "9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a", + "author": { + "email": "wizard@roborooter.com", + "name": "Francis Gulotta" + }, + "message": "[unix] Move setting up the baudrate to the end of the open()\n\n- Test 1000000 baud", + "distinct": true, + "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/commits/9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z", + "org": { + "id": 8947774, + "login": "EmergingTechnologyAdvisors", + "gravatar_id": "", + "url": "https://api.github.com/orgs/EmergingTechnologyAdvisors", + "avatar_url": "https://avatars.githubusercontent.com/u/8947774?" + } + }, + { + "id": "6263117471", + "type": "IssueCommentEvent", + "actor": { + "id": 737750, + "login": "samuelkarp", + "display_login": "samuelkarp", + "gravatar_id": "", + "url": "https://api.github.com/users/samuelkarp", + "avatar_url": "https://avatars.githubusercontent.com/u/737750?" + }, + "repo": { + "id": 59514412, + "name": "awslabs/amazon-ecr-credential-helper", + "url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper" + }, + "payload": { + "action": "created", + "issue": { + "url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49", + "repository_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper", + "labels_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49/labels{/name}", + "comments_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49/comments", + "events_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49/events", + "html_url": "https://github.com/awslabs/amazon-ecr-credential-helper/issues/49", + "id": 241526602, + "number": 49, + "title": "no basic auth credentials yet AWS CLI has access", + "user": { + "login": "guyisra", + "id": 1073521, + "avatar_url": "https://avatars5.githubusercontent.com/u/1073521?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/guyisra", + "html_url": "https://github.com/guyisra", + "followers_url": "https://api.github.com/users/guyisra/followers", + "following_url": "https://api.github.com/users/guyisra/following{/other_user}", + "gists_url": "https://api.github.com/users/guyisra/gists{/gist_id}", + "starred_url": "https://api.github.com/users/guyisra/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/guyisra/subscriptions", + "organizations_url": "https://api.github.com/users/guyisra/orgs", + "repos_url": "https://api.github.com/users/guyisra/repos", + "events_url": "https://api.github.com/users/guyisra/events{/privacy}", + "received_events_url": "https://api.github.com/users/guyisra/received_events", + "type": "User", + "site_admin": false + }, + "labels": [], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": null, + "comments": 3, + "created_at": "2017-07-09T13:59:15Z", + "updated_at": "2017-07-15T17:06:46Z", + "closed_at": null, + "body": "I am using Docker v17 and for some reason when trying to push to ECR I get no basic auth credentials.\r\n\r\nThis doesn't happen if I manually login with `aws ecr get-login ...`\r\n\r\nthe policy is configured correctly, I can run other AWS commands.\r\nIt gives the same response with either a profile with the proper policy or with the access key and secret explicitly set.." + }, + "comment": { + "url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/comments/315547939", + "html_url": "https://github.com/awslabs/amazon-ecr-credential-helper/issues/49#issuecomment-315547939", + "issue_url": "https://api.github.com/repos/awslabs/amazon-ecr-credential-helper/issues/49", + "id": 315547939, + "user": { + "login": "samuelkarp", + "id": 737750, + "avatar_url": "https://avatars7.githubusercontent.com/u/737750?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/samuelkarp", + "html_url": "https://github.com/samuelkarp", + "followers_url": "https://api.github.com/users/samuelkarp/followers", + "following_url": "https://api.github.com/users/samuelkarp/following{/other_user}", + "gists_url": "https://api.github.com/users/samuelkarp/gists{/gist_id}", + "starred_url": "https://api.github.com/users/samuelkarp/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/samuelkarp/subscriptions", + "organizations_url": "https://api.github.com/users/samuelkarp/orgs", + "repos_url": "https://api.github.com/users/samuelkarp/repos", + "events_url": "https://api.github.com/users/samuelkarp/events{/privacy}", + "received_events_url": "https://api.github.com/users/samuelkarp/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2017-07-15T17:06:46Z", + "updated_at": "2017-07-15T17:06:46Z", + "body": "@mskutin Thanks for providing the log; that's very helpful. Can you let me know what region this was for so I can investigate further?" + } + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z", + "org": { + "id": 3299148, + "login": "awslabs", + "gravatar_id": "", + "url": "https://api.github.com/orgs/awslabs", + "avatar_url": "https://avatars.githubusercontent.com/u/3299148?" + } + }, + { + "id": "6263117468", + "type": "IssueCommentEvent", + "actor": { + "id": 1645308, + "login": "almereyda", + "display_login": "almereyda", + "gravatar_id": "", + "url": "https://api.github.com/users/almereyda", + "avatar_url": "https://avatars.githubusercontent.com/u/1645308?" + }, + "repo": { + "id": 22657662, + "name": "wsargent/docker-cheat-sheet", + "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet" + }, + "payload": { + "action": "created", + "issue": { + "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136", + "repository_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet", + "labels_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136/labels{/name}", + "comments_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136/comments", + "events_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136/events", + "html_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136", + "id": 243181907, + "number": 136, + "title": "Volumes can be files", + "user": { + "login": "phoen1x", + "id": 2550793, + "avatar_url": "https://avatars7.githubusercontent.com/u/2550793?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/phoen1x", + "html_url": "https://github.com/phoen1x", + "followers_url": "https://api.github.com/users/phoen1x/followers", + "following_url": "https://api.github.com/users/phoen1x/following{/other_user}", + "gists_url": "https://api.github.com/users/phoen1x/gists{/gist_id}", + "starred_url": "https://api.github.com/users/phoen1x/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/phoen1x/subscriptions", + "organizations_url": "https://api.github.com/users/phoen1x/orgs", + "repos_url": "https://api.github.com/users/phoen1x/repos", + "events_url": "https://api.github.com/users/phoen1x/events{/privacy}", + "received_events_url": "https://api.github.com/users/phoen1x/received_events", + "type": "User", + "site_admin": false + }, + "labels": [], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": null, + "comments": 0, + "created_at": "2017-07-15T15:28:10Z", + "updated_at": "2017-07-15T17:06:46Z", + "closed_at": null, + "pull_request": { + "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/pulls/136", + "html_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136", + "diff_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136.diff", + "patch_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136.patch" + }, + "body": "Just wanted to add that is possible to mount files as volumes. \r\n\r\nDon't know if that is worth mentioning. But it can be useful if you want to toy around with a image from [Docker Hub](https://hub.docker.com) without writing your own Dockerfile." + }, + "comment": { + "url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/comments/315547938", + "html_url": "https://github.com/wsargent/docker-cheat-sheet/pull/136#issuecomment-315547938", + "issue_url": "https://api.github.com/repos/wsargent/docker-cheat-sheet/issues/136", + "id": 315547938, + "user": { + "login": "almereyda", + "id": 1645308, + "avatar_url": "https://avatars4.githubusercontent.com/u/1645308?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/almereyda", + "html_url": "https://github.com/almereyda", + "followers_url": "https://api.github.com/users/almereyda/followers", + "following_url": "https://api.github.com/users/almereyda/following{/other_user}", + "gists_url": "https://api.github.com/users/almereyda/gists{/gist_id}", + "starred_url": "https://api.github.com/users/almereyda/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/almereyda/subscriptions", + "organizations_url": "https://api.github.com/users/almereyda/orgs", + "repos_url": "https://api.github.com/users/almereyda/repos", + "events_url": "https://api.github.com/users/almereyda/events{/privacy}", + "received_events_url": "https://api.github.com/users/almereyda/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2017-07-15T17:06:46Z", + "updated_at": "2017-07-15T17:06:46Z", + "body": "Indeed, I do that all the time when modifying assets that were turned into immutable images already." + } + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z" + }, + { + "id": "6263117464", + "type": "PushEvent", + "actor": { + "id": 19437824, + "login": "keriwheatley", + "display_login": "keriwheatley", + "gravatar_id": "", + "url": "https://api.github.com/users/keriwheatley", + "avatar_url": "https://avatars.githubusercontent.com/u/19437824?" + }, + "repo": { + "id": 91394098, + "name": "keriwheatley/coursework", + "url": "https://api.github.com/repos/keriwheatley/coursework" + }, + "payload": { + "push_id": 1861573800, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "490f194beb4be216ed955d187aee265443dd532c", + "before": "14034277c8e715f9988686d85701b501845705e7", + "commits": [ + { + "sha": "490f194beb4be216ed955d187aee265443dd532c", + "author": { + "email": "keri.wheatley@civitaslearning.com", + "name": "Keri Wheatley" + }, + "message": "updates to twitter_popularity", + "distinct": true, + "url": "https://api.github.com/repos/keriwheatley/coursework/commits/490f194beb4be216ed955d187aee265443dd532c" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z" + }, + { + "id": "6263117462", + "type": "CreateEvent", + "actor": { + "id": 12358972, + "login": "CodePipeline-Test", + "display_login": "CodePipeline-Test", + "gravatar_id": "", + "url": "https://api.github.com/users/CodePipeline-Test", + "avatar_url": "https://avatars.githubusercontent.com/u/12358972?" + }, + "repo": { + "id": 63971386, + "name": "CodePipeline-Test/feature-tests", + "url": "https://api.github.com/repos/CodePipeline-Test/feature-tests" + }, + "payload": { + "ref": "job-worker-features-V5zkpTEUgBlA4TOEJrWq", + "ref_type": "branch", + "master_branch": "master", + "description": "for feature tests", + "pusher_type": "user" + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z" + }, + { + "id": "6263117460", + "type": "WatchEvent", + "actor": { + "id": 9091565, + "login": "chiprunner1995", + "display_login": "chiprunner1995", + "gravatar_id": "", + "url": "https://api.github.com/users/chiprunner1995", + "avatar_url": "https://avatars.githubusercontent.com/u/9091565?" + }, + "repo": { + "id": 308512, + "name": "psake/psake", + "url": "https://api.github.com/repos/psake/psake" + }, + "payload": { + "action": "started" + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z", + "org": { + "id": 1007585, + "login": "psake", + "gravatar_id": "", + "url": "https://api.github.com/orgs/psake", + "avatar_url": "https://avatars.githubusercontent.com/u/1007585?" + } + }, + { + "id": "6263117459", + "type": "PushEvent", + "actor": { + "id": 30199151, + "login": "Geoffers888", + "display_login": "Geoffers888", + "gravatar_id": "", + "url": "https://api.github.com/users/Geoffers888", + "avatar_url": "https://avatars.githubusercontent.com/u/30199151?" + }, + "repo": { + "id": 97330344, + "name": "Geoffers888/Console-Boxes", + "url": "https://api.github.com/repos/Geoffers888/Console-Boxes" + }, + "payload": { + "push_id": 1861573799, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "46f85052c269c7ede354a698e05e5ef5359bc71b", + "before": "ecb8a45cc1e49ee60ffa880eba8219b294ec44f5", + "commits": [ + { + "sha": "46f85052c269c7ede354a698e05e5ef5359bc71b", + "author": { + "email": "geoff.cowin@gmail.com", + "name": "Geoffers888" + }, + "message": "Create README.md", + "distinct": true, + "url": "https://api.github.com/repos/Geoffers888/Console-Boxes/commits/46f85052c269c7ede354a698e05e5ef5359bc71b" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z" + }, + { + "id": "6263117454", + "type": "PushEvent", + "actor": { + "id": 8517910, + "login": "LombiqBot", + "display_login": "LombiqBot", + "gravatar_id": "", + "url": "https://api.github.com/users/LombiqBot", + "avatar_url": "https://avatars.githubusercontent.com/u/8517910?" + }, + "repo": { + "id": 46624662, + "name": "Lombiq/Orchard-External-Pages", + "url": "https://api.github.com/repos/Lombiq/Orchard-External-Pages" + }, + "payload": { + "push_id": 1861573796, + "size": 0, + "distinct_size": 0, + "ref": "refs/heads/issue/OSOE-7", + "head": "a630eb8494f07e6f11a5bc396a0829d5aa690c5f", + "before": "a630eb8494f07e6f11a5bc396a0829d5aa690c5f", + "commits": [] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z", + "org": { + "id": 8158177, + "login": "Lombiq", + "gravatar_id": "", + "url": "https://api.github.com/orgs/Lombiq", + "avatar_url": "https://avatars.githubusercontent.com/u/8158177?" + } + }, + { + "id": "6263117451", + "type": "PullRequestEvent", + "actor": { + "id": 25966, + "login": "reconbot", + "display_login": "reconbot", + "gravatar_id": "", + "url": "https://api.github.com/users/reconbot", + "avatar_url": "https://avatars.githubusercontent.com/u/25966?" + }, + "repo": { + "id": 893522, + "name": "EmergingTechnologyAdvisors/node-serialport", + "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport" + }, + "payload": { + "action": "closed", + "number": 1235, + "pull_request": { + "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235", + "id": 130722112, + "html_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235", + "diff_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235.diff", + "patch_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235.patch", + "issue_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235", + "number": 1235, + "state": "closed", + "locked": false, + "title": "[unix] Move setting up the baudrate to the end of the open() to better support custom baudrates", + "user": { + "login": "reconbot", + "id": 25966, + "avatar_url": "https://avatars6.githubusercontent.com/u/25966?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/reconbot", + "html_url": "https://github.com/reconbot", + "followers_url": "https://api.github.com/users/reconbot/followers", + "following_url": "https://api.github.com/users/reconbot/following{/other_user}", + "gists_url": "https://api.github.com/users/reconbot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/reconbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/reconbot/subscriptions", + "organizations_url": "https://api.github.com/users/reconbot/orgs", + "repos_url": "https://api.github.com/users/reconbot/repos", + "events_url": "https://api.github.com/users/reconbot/events{/privacy}", + "received_events_url": "https://api.github.com/users/reconbot/received_events", + "type": "User", + "site_admin": false + }, + "body": "- Test 1000000 baud\r\n\r\ncloses #1077", + "created_at": "2017-07-15T16:53:28Z", + "updated_at": "2017-07-15T17:06:45Z", + "closed_at": "2017-07-15T17:06:45Z", + "merged_at": "2017-07-15T17:06:45Z", + "merge_commit_sha": "9c67ee2a43c0e12a5d8d0345e42c866f550d5d0a", + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "milestone": null, + "commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/commits", + "review_comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/comments", + "review_comment_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235/comments", + "statuses_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/e57b3d685f6497ebe8669ce8b05894bacd895177", + "head": { + "label": "EmergingTechnologyAdvisors:1000000-baud", + "ref": "1000000-baud", + "sha": "e57b3d685f6497ebe8669ce8b05894bacd895177", + "user": { + "login": "EmergingTechnologyAdvisors", + "id": 8947774, + "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/EmergingTechnologyAdvisors", + "html_url": "https://github.com/EmergingTechnologyAdvisors", + "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", + "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", + "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", + "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", + "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", + "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", + "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", + "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", + "type": "Organization", + "site_admin": false + }, + "repo": { + "id": 893522, + "name": "node-serialport", + "full_name": "EmergingTechnologyAdvisors/node-serialport", + "owner": { + "login": "EmergingTechnologyAdvisors", + "id": 8947774, + "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/EmergingTechnologyAdvisors", + "html_url": "https://github.com/EmergingTechnologyAdvisors", + "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", + "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", + "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", + "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", + "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", + "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", + "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", + "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", + "type": "Organization", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", + "description": "Node.js package to access serial ports for reading and writing. Welcome your robotic JavaScript overlords. Better yet, program them!", + "fork": false, + "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport", + "forks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/forks", + "keys_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/teams", + "hooks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/hooks", + "issue_events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/events{/number}", + "events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/events", + "assignees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/assignees{/user}", + "branches_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/branches{/branch}", + "tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/tags", + "blobs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/{sha}", + "languages_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/languages", + "stargazers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/stargazers", + "contributors_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contributors", + "subscribers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscribers", + "subscription_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscription", + "commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contents/{+path}", + "compare_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/merges", + "archive_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/downloads", + "issues_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues{/number}", + "pulls_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls{/number}", + "milestones_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/milestones{/number}", + "notifications_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/labels{/name}", + "releases_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/releases{/id}", + "deployments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/deployments", + "created_at": "2010-09-07T12:24:28Z", + "updated_at": "2017-07-14T16:30:58Z", + "pushed_at": "2017-07-15T17:06:45Z", + "git_url": "git://github.com/EmergingTechnologyAdvisors/node-serialport.git", + "ssh_url": "git@github.com:EmergingTechnologyAdvisors/node-serialport.git", + "clone_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport.git", + "svn_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", + "homepage": "", + "size": 1914, + "stargazers_count": 2829, + "watchers_count": 2829, + "language": "JavaScript", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "forks_count": 601, + "mirror_url": null, + "open_issues_count": 30, + "forks": 601, + "open_issues": 30, + "watchers": 2829, + "default_branch": "master" + } + }, + "base": { + "label": "EmergingTechnologyAdvisors:master", + "ref": "master", + "sha": "ee7315f59c7698811f4f76405383f18680843926", + "user": { + "login": "EmergingTechnologyAdvisors", + "id": 8947774, + "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/EmergingTechnologyAdvisors", + "html_url": "https://github.com/EmergingTechnologyAdvisors", + "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", + "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", + "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", + "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", + "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", + "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", + "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", + "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", + "type": "Organization", + "site_admin": false + }, + "repo": { + "id": 893522, + "name": "node-serialport", + "full_name": "EmergingTechnologyAdvisors/node-serialport", + "owner": { + "login": "EmergingTechnologyAdvisors", + "id": 8947774, + "avatar_url": "https://avatars7.githubusercontent.com/u/8947774?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/EmergingTechnologyAdvisors", + "html_url": "https://github.com/EmergingTechnologyAdvisors", + "followers_url": "https://api.github.com/users/EmergingTechnologyAdvisors/followers", + "following_url": "https://api.github.com/users/EmergingTechnologyAdvisors/following{/other_user}", + "gists_url": "https://api.github.com/users/EmergingTechnologyAdvisors/gists{/gist_id}", + "starred_url": "https://api.github.com/users/EmergingTechnologyAdvisors/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/EmergingTechnologyAdvisors/subscriptions", + "organizations_url": "https://api.github.com/users/EmergingTechnologyAdvisors/orgs", + "repos_url": "https://api.github.com/users/EmergingTechnologyAdvisors/repos", + "events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/events{/privacy}", + "received_events_url": "https://api.github.com/users/EmergingTechnologyAdvisors/received_events", + "type": "Organization", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", + "description": "Node.js package to access serial ports for reading and writing. Welcome your robotic JavaScript overlords. Better yet, program them!", + "fork": false, + "url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport", + "forks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/forks", + "keys_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/teams", + "hooks_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/hooks", + "issue_events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/events{/number}", + "events_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/events", + "assignees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/assignees{/user}", + "branches_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/branches{/branch}", + "tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/tags", + "blobs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/{sha}", + "languages_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/languages", + "stargazers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/stargazers", + "contributors_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contributors", + "subscribers_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscribers", + "subscription_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/subscription", + "commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/contents/{+path}", + "compare_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/merges", + "archive_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/downloads", + "issues_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues{/number}", + "pulls_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls{/number}", + "milestones_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/milestones{/number}", + "notifications_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/labels{/name}", + "releases_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/releases{/id}", + "deployments_url": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/deployments", + "created_at": "2010-09-07T12:24:28Z", + "updated_at": "2017-07-14T16:30:58Z", + "pushed_at": "2017-07-15T17:06:45Z", + "git_url": "git://github.com/EmergingTechnologyAdvisors/node-serialport.git", + "ssh_url": "git@github.com:EmergingTechnologyAdvisors/node-serialport.git", + "clone_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport.git", + "svn_url": "https://github.com/EmergingTechnologyAdvisors/node-serialport", + "homepage": "", + "size": 1914, + "stargazers_count": 2829, + "watchers_count": 2829, + "language": "JavaScript", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": false, + "has_pages": true, + "forks_count": 601, + "mirror_url": null, + "open_issues_count": 30, + "forks": 601, + "open_issues": 30, + "watchers": 2829, + "default_branch": "master" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235" + }, + "html": { + "href": "https://github.com/EmergingTechnologyAdvisors/node-serialport/pull/1235" + }, + "issue": { + "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235" + }, + "comments": { + "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/issues/1235/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/pulls/1235/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/EmergingTechnologyAdvisors/node-serialport/statuses/e57b3d685f6497ebe8669ce8b05894bacd895177" + } + }, + "merged": true, + "mergeable": null, + "rebaseable": null, + "mergeable_state": "unknown", + "merged_by": { + "login": "reconbot", + "id": 25966, + "avatar_url": "https://avatars6.githubusercontent.com/u/25966?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/reconbot", + "html_url": "https://github.com/reconbot", + "followers_url": "https://api.github.com/users/reconbot/followers", + "following_url": "https://api.github.com/users/reconbot/following{/other_user}", + "gists_url": "https://api.github.com/users/reconbot/gists{/gist_id}", + "starred_url": "https://api.github.com/users/reconbot/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/reconbot/subscriptions", + "organizations_url": "https://api.github.com/users/reconbot/orgs", + "repos_url": "https://api.github.com/users/reconbot/repos", + "events_url": "https://api.github.com/users/reconbot/events{/privacy}", + "received_events_url": "https://api.github.com/users/reconbot/received_events", + "type": "User", + "site_admin": false + }, + "comments": 0, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 24, + "deletions": 14, + "changed_files": 2 + } + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z", + "org": { + "id": 8947774, + "login": "EmergingTechnologyAdvisors", + "gravatar_id": "", + "url": "https://api.github.com/orgs/EmergingTechnologyAdvisors", + "avatar_url": "https://avatars.githubusercontent.com/u/8947774?" + } + }, + { + "id": "6263117447", + "type": "PushEvent", + "actor": { + "id": 11887843, + "login": "trimox", + "display_login": "trimox", + "gravatar_id": "", + "url": "https://api.github.com/users/trimox", + "avatar_url": "https://avatars.githubusercontent.com/u/11887843?" + }, + "repo": { + "id": 88184430, + "name": "trimox/angular-mdc-web", + "url": "https://api.github.com/repos/trimox/angular-mdc-web" + }, + "payload": { + "push_id": 1861573792, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "59de0a8bfb229e7e72a1960132fdf24f0a770a08", + "before": "27327b3a3cb4e58ddb1b1188cb0f04092d850106", + "commits": [ + { + "sha": "59de0a8bfb229e7e72a1960132fdf24f0a770a08", + "author": { + "email": "trimoxal@gmail.com", + "name": "Dominic Carretto" + }, + "message": "fix(snackbar): Fix actionHandler still required if actionText is empty", + "distinct": true, + "url": "https://api.github.com/repos/trimox/angular-mdc-web/commits/59de0a8bfb229e7e72a1960132fdf24f0a770a08" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:46Z" + }, + { + "id": "6263117445", + "type": "WatchEvent", + "actor": { + "id": 1006434, + "login": "enorrmann", + "display_login": "enorrmann", + "gravatar_id": "", + "url": "https://api.github.com/users/enorrmann", + "avatar_url": "https://avatars.githubusercontent.com/u/1006434?" + }, + "repo": { + "id": 14699489, + "name": "walmik/scribbletune", + "url": "https://api.github.com/repos/walmik/scribbletune" + }, + "payload": { + "action": "started" + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117444", + "type": "PushEvent", + "actor": { + "id": 24412103, + "login": "james341", + "display_login": "james341", + "gravatar_id": "", + "url": "https://api.github.com/users/james341", + "avatar_url": "https://avatars.githubusercontent.com/u/24412103?" + }, + "repo": { + "id": 96979484, + "name": "james341/loading-yan-rp", + "url": "https://api.github.com/repos/james341/loading-yan-rp" + }, + "payload": { + "push_id": 1861573791, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "16bb35eb4a43d916a40155996c9d7dfadb007573", + "before": "ad4b96a5b924783e42d1d0cbf0fd1b5cba3cbd2f", + "commits": [ + { + "sha": "16bb35eb4a43d916a40155996c9d7dfadb007573", + "author": { + "email": "taine049@gmail.com", + "name": "james341" + }, + "message": "Add files via upload", + "distinct": true, + "url": "https://api.github.com/repos/james341/loading-yan-rp/commits/16bb35eb4a43d916a40155996c9d7dfadb007573" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117441", + "type": "PushEvent", + "actor": { + "id": 4676211, + "login": "kanke", + "display_login": "kanke", + "gravatar_id": "", + "url": "https://api.github.com/users/kanke", + "avatar_url": "https://avatars.githubusercontent.com/u/4676211?" + }, + "repo": { + "id": 97262451, + "name": "kanke/RedisServerClone", + "url": "https://api.github.com/repos/kanke/RedisServerClone" + }, + "payload": { + "push_id": 1861573790, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "e6312819f0acdc40008b06ae7a2c6c211c2f1db0", + "before": "f9a4fe7e866181c74fbc9352310fbc6c539d2aff", + "commits": [ + { + "sha": "e6312819f0acdc40008b06ae7a2c6c211c2f1db0", + "author": { + "email": "sugarkanke@yahoo.com", + "name": "Kanke" + }, + "message": "Adding gitignore and readme.md content. Code cleanup.", + "distinct": true, + "url": "https://api.github.com/repos/kanke/RedisServerClone/commits/e6312819f0acdc40008b06ae7a2c6c211c2f1db0" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117440", + "type": "PushEvent", + "actor": { + "id": 16622965, + "login": "jainhitesh9998", + "display_login": "jainhitesh9998", + "gravatar_id": "", + "url": "https://api.github.com/users/jainhitesh9998", + "avatar_url": "https://avatars.githubusercontent.com/u/16622965?" + }, + "repo": { + "id": 94244445, + "name": "jainhitesh9998/WebDevelopment", + "url": "https://api.github.com/repos/jainhitesh9998/WebDevelopment" + }, + "payload": { + "push_id": 1861573789, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "9e3c3f5f437fbc1f21a30f19f764787b86a393be", + "before": "d69d496b80a5806406f2313d67e63f3adf61b97e", + "commits": [ + { + "sha": "9e3c3f5f437fbc1f21a30f19f764787b86a393be", + "author": { + "email": "jainhitesh9998@gmail.com", + "name": "Hitesh C" + }, + "message": "added sounds for the clone", + "distinct": true, + "url": "https://api.github.com/repos/jainhitesh9998/WebDevelopment/commits/9e3c3f5f437fbc1f21a30f19f764787b86a393be" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117437", + "type": "PushEvent", + "actor": { + "id": 1491646, + "login": "MikroAcse", + "display_login": "MikroAcse", + "gravatar_id": "", + "url": "https://api.github.com/users/MikroAcse", + "avatar_url": "https://avatars.githubusercontent.com/u/1491646?" + }, + "repo": { + "id": 96892535, + "name": "MikroAcse/VariousTelegramBots", + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots" + }, + "payload": { + "push_id": 1861573788, + "size": 11, + "distinct_size": 11, + "ref": "refs/heads/dev", + "head": "7ef25bf6aad45c9da53a2d5918e553c68cd69dd4", + "before": "931cef7db8ec69cc951fe8a5ecc2b909397e29a4", + "commits": [ + { + "sha": "88b9e4e53f62ff7c9597f66d9e45a0a9be5fe1ca", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "upgrade Node.js version", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/88b9e4e53f62ff7c9597f66d9e45a0a9be5fe1ca" + }, + { + "sha": "d5b91bac58a8c3b88ddd9634578cb3beebb31015", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Update Node js version", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/d5b91bac58a8c3b88ddd9634578cb3beebb31015" + }, + { + "sha": "37cd86961e36e64c8ccd7873bbccc200b920d308", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Fix", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/37cd86961e36e64c8ccd7873bbccc200b920d308" + }, + { + "sha": "471451fd46b9bed62eef062553f480e788c24a3c", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Merge branch 'master' into dev\n\n# Conflicts:\n#\tapp.js", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/471451fd46b9bed62eef062553f480e788c24a3c" + }, + { + "sha": "8f5be591fae47f1ff051f992176faeed8fe3c2d7", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Removed unnecessary dependency and updated README.md", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/8f5be591fae47f1ff051f992176faeed8fe3c2d7" + }, + { + "sha": "d239750fbb26f13daf50a14e1c4a23375df9c5d9", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Update README", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/d239750fbb26f13daf50a14e1c4a23375df9c5d9" + }, + { + "sha": "94adaefc2b4107db89cdbc045a6a106724f12a2d", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Fix in readme", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/94adaefc2b4107db89cdbc045a6a106724f12a2d" + }, + { + "sha": "da8009c4da182c036efbc7a8e9d9353d1282d5ed", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Added version to readme", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/da8009c4da182c036efbc7a8e9d9353d1282d5ed" + }, + { + "sha": "1590092c64e774633040419b69d60d98197ddbde", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Removed requirement of deleted dependency", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/1590092c64e774633040419b69d60d98197ddbde" + }, + { + "sha": "1986905b1d32654a20916fafc60c7484ff85841a", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Yes or no in ChooseBot, slight changes in QuoteBot regexp", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/1986905b1d32654a20916fafc60c7484ff85841a" + }, + { + "sha": "7ef25bf6aad45c9da53a2d5918e553c68cd69dd4", + "author": { + "email": "mike.kroace@gmail.com", + "name": "Vitaly Rudenko" + }, + "message": "Merge commit '1986905b1d32654a20916fafc60c7484ff85841a' into dev", + "distinct": true, + "url": "https://api.github.com/repos/MikroAcse/VariousTelegramBots/commits/7ef25bf6aad45c9da53a2d5918e553c68cd69dd4" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117435", + "type": "PushEvent", + "actor": { + "id": 12949454, + "login": "jarifibrahim", + "display_login": "jarifibrahim", + "gravatar_id": "", + "url": "https://api.github.com/users/jarifibrahim", + "avatar_url": "https://avatars.githubusercontent.com/u/12949454?" + }, + "repo": { + "id": 93039796, + "name": "jarifibrahim/OpenSourceHelpCommunity.github.io", + "url": "https://api.github.com/repos/jarifibrahim/OpenSourceHelpCommunity.github.io" + }, + "payload": { + "push_id": 1861573787, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/issue-4", + "head": "4b7341d9b7bb95f5f0e1d50831a9c978fc4fceb4", + "before": "57c0a65ee93de1955ad5691585a51c358188f311", + "commits": [ + { + "sha": "4b7341d9b7bb95f5f0e1d50831a9c978fc4fceb4", + "author": { + "email": "jarifibrahim@gmail.com", + "name": "Ibrahim Jarif" + }, + "message": "Add travs.yml", + "distinct": true, + "url": "https://api.github.com/repos/jarifibrahim/OpenSourceHelpCommunity.github.io/commits/4b7341d9b7bb95f5f0e1d50831a9c978fc4fceb4" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117430", + "type": "IssueCommentEvent", + "actor": { + "id": 849609, + "login": "wrrn", + "display_login": "wrrn", + "gravatar_id": "", + "url": "https://api.github.com/users/wrrn", + "avatar_url": "https://avatars.githubusercontent.com/u/849609?" + }, + "repo": { + "id": 23096959, + "name": "golang/go", + "url": "https://api.github.com/repos/golang/go" + }, + "payload": { + "action": "created", + "issue": { + "url": "https://api.github.com/repos/golang/go/issues/21017", + "repository_url": "https://api.github.com/repos/golang/go", + "labels_url": "https://api.github.com/repos/golang/go/issues/21017/labels{/name}", + "comments_url": "https://api.github.com/repos/golang/go/issues/21017/comments", + "events_url": "https://api.github.com/repos/golang/go/issues/21017/events", + "html_url": "https://github.com/golang/go/issues/21017", + "id": 243177572, + "number": 21017, + "title": "Gophercon: Contributor Workshop Registration", + "user": { + "login": "jessfraz", + "id": 1445228, + "avatar_url": "https://avatars6.githubusercontent.com/u/1445228?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jessfraz", + "html_url": "https://github.com/jessfraz", + "followers_url": "https://api.github.com/users/jessfraz/followers", + "following_url": "https://api.github.com/users/jessfraz/following{/other_user}", + "gists_url": "https://api.github.com/users/jessfraz/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jessfraz/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jessfraz/subscriptions", + "organizations_url": "https://api.github.com/users/jessfraz/orgs", + "repos_url": "https://api.github.com/users/jessfraz/repos", + "events_url": "https://api.github.com/users/jessfraz/events{/privacy}", + "received_events_url": "https://api.github.com/users/jessfraz/received_events", + "type": "User", + "site_admin": false + }, + "labels": [ + { + "id": 150880243, + "url": "https://api.github.com/repos/golang/go/labels/HelpWanted", + "name": "HelpWanted", + "color": "fbca04", + "default": false + } + ], + "state": "open", + "locked": false, + "assignee": null, + "assignees": [], + "milestone": { + "url": "https://api.github.com/repos/golang/go/milestones/22", + "html_url": "https://github.com/golang/go/milestone/22", + "labels_url": "https://api.github.com/repos/golang/go/milestones/22/labels", + "id": 1067491, + "number": 22, + "title": "Unreleased", + "description": "Issues that do not affect released Go code and binaries.\r\n", + "creator": { + "login": "rsc", + "id": 104030, + "avatar_url": "https://avatars5.githubusercontent.com/u/104030?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/rsc", + "html_url": "https://github.com/rsc", + "followers_url": "https://api.github.com/users/rsc/followers", + "following_url": "https://api.github.com/users/rsc/following{/other_user}", + "gists_url": "https://api.github.com/users/rsc/gists{/gist_id}", + "starred_url": "https://api.github.com/users/rsc/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/rsc/subscriptions", + "organizations_url": "https://api.github.com/users/rsc/orgs", + "repos_url": "https://api.github.com/users/rsc/repos", + "events_url": "https://api.github.com/users/rsc/events{/privacy}", + "received_events_url": "https://api.github.com/users/rsc/received_events", + "type": "User", + "site_admin": false + }, + "open_issues": 707, + "closed_issues": 918, + "state": "open", + "created_at": "2015-04-14T18:48:22Z", + "updated_at": "2017-07-15T17:06:04Z", + "due_on": "2099-12-31T08:00:00Z", + "closed_at": null + }, + "comments": 14, + "created_at": "2017-07-15T14:13:29Z", + "updated_at": "2017-07-15T17:06:43Z", + "closed_at": null, + "body": "Please do not comment here until the Contributor Workshop begins.\r\n\r\nDuring the workshop leave a comment with your Gerritt profile ID here." + }, + "comment": { + "url": "https://api.github.com/repos/golang/go/issues/comments/315547934", + "html_url": "https://github.com/golang/go/issues/21017#issuecomment-315547934", + "issue_url": "https://api.github.com/repos/golang/go/issues/21017", + "id": 315547934, + "user": { + "login": "wrrn", + "id": 849609, + "avatar_url": "https://avatars7.githubusercontent.com/u/849609?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/wrrn", + "html_url": "https://github.com/wrrn", + "followers_url": "https://api.github.com/users/wrrn/followers", + "following_url": "https://api.github.com/users/wrrn/following{/other_user}", + "gists_url": "https://api.github.com/users/wrrn/gists{/gist_id}", + "starred_url": "https://api.github.com/users/wrrn/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/wrrn/subscriptions", + "organizations_url": "https://api.github.com/users/wrrn/orgs", + "repos_url": "https://api.github.com/users/wrrn/repos", + "events_url": "https://api.github.com/users/wrrn/events{/privacy}", + "received_events_url": "https://api.github.com/users/wrrn/received_events", + "type": "User", + "site_admin": false + }, + "created_at": "2017-07-15T17:06:43Z", + "updated_at": "2017-07-15T17:06:43Z", + "body": "22590" + } + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z", + "org": { + "id": 4314092, + "login": "golang", + "gravatar_id": "", + "url": "https://api.github.com/orgs/golang", + "avatar_url": "https://avatars.githubusercontent.com/u/4314092?" + } + }, + { + "id": "6263117428", + "type": "PushEvent", + "actor": { + "id": 6938676, + "login": "Ordinastie", + "display_login": "Ordinastie", + "gravatar_id": "", + "url": "https://api.github.com/users/Ordinastie", + "avatar_url": "https://avatars.githubusercontent.com/u/6938676?" + }, + "repo": { + "id": 17756561, + "name": "Ordinastie/MalisisDoors", + "url": "https://api.github.com/repos/Ordinastie/MalisisDoors" + }, + "payload": { + "push_id": 1861573783, + "size": 2, + "distinct_size": 2, + "ref": "refs/heads/1.12", + "head": "07334b1700ec9cd173c7560f293b7dd10dc24fd9", + "before": "ee8e1058833056afdcac559c22518b3706b3657f", + "commits": [ + { + "sha": "52080012d79ae0320392379b5d054f3e17ec1b98", + "author": { + "email": "ordinastie@hotmail.com", + "name": "Ordinastie" + }, + "message": "Fixed getRegistryType()", + "distinct": true, + "url": "https://api.github.com/repos/Ordinastie/MalisisDoors/commits/52080012d79ae0320392379b5d054f3e17ec1b98" + }, + { + "sha": "07334b1700ec9cd173c7560f293b7dd10dc24fd9", + "author": { + "email": "ordinastie@hotmail.com", + "name": "Ordinastie" + }, + "message": "Updated forgegradle and curseforge version", + "distinct": true, + "url": "https://api.github.com/repos/Ordinastie/MalisisDoors/commits/07334b1700ec9cd173c7560f293b7dd10dc24fd9" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117427", + "type": "DeleteEvent", + "actor": { + "id": 227909, + "login": "amcdnl", + "display_login": "amcdnl", + "gravatar_id": "", + "url": "https://api.github.com/users/amcdnl", + "avatar_url": "https://avatars.githubusercontent.com/u/227909?" + }, + "repo": { + "id": 94944874, + "name": "amcdnl/material2", + "url": "https://api.github.com/repos/amcdnl/material2" + }, + "payload": { + "ref": "autocomplete-demos", + "ref_type": "branch", + "pusher_type": "user" + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + }, + { + "id": "6263117426", + "type": "PushEvent", + "actor": { + "id": 16347325, + "login": "zxui", + "display_login": "zxui", + "gravatar_id": "", + "url": "https://api.github.com/users/zxui", + "avatar_url": "https://avatars.githubusercontent.com/u/16347325?" + }, + "repo": { + "id": 88623154, + "name": "zxui/auto-admin", + "url": "https://api.github.com/repos/zxui/auto-admin" + }, + "payload": { + "push_id": 1861573782, + "size": 1, + "distinct_size": 1, + "ref": "refs/heads/master", + "head": "70d47755fde8a5c4cfde101ba65caa6c1d6fcdb2", + "before": "f673e6b191197827bddb31bcffea61611e8a50b0", + "commits": [ + { + "sha": "70d47755fde8a5c4cfde101ba65caa6c1d6fcdb2", + "author": { + "email": "zxshen@qq.com", + "name": "zxui" + }, + "message": "update", + "distinct": true, + "url": "https://api.github.com/repos/zxui/auto-admin/commits/70d47755fde8a5c4cfde101ba65caa6c1d6fcdb2" + } + ] + }, + "public": true, + "created_at": "2017-07-15T17:06:45Z" + } +] diff --git a/test/fixtures/typescript-effect-schema/main.ts b/test/fixtures/typescript-effect-schema/main.ts index c2bf066b..944b021f 100644 --- a/test/fixtures/typescript-effect-schema/main.ts +++ b/test/fixtures/typescript-effect-schema/main.ts @@ -10,7 +10,7 @@ const value = JSON.parse(json.toString()); let schema = TopLevel.TopLevel ?? TopLevel.TopLevelElement; if (!schema) { // Sometimes key is prefixed with funPrefixes (e.g. 2df80.json) - Object.keys(TopLevel).some(key => { + Object.keys(TopLevel).some((key) => { if (key.endsWith("TopLevel") || key.endsWith("TopLevelElement")) { schema = TopLevel[key]; return true; @@ -24,7 +24,7 @@ if (!schema) { let backToJson: string; if (Array.isArray(value)) { - const parsedValue = value.map(v => { + const parsedValue = value.map((v) => { return Schema.decodeUnknownSync(schema)(v); }); backToJson = JSON.stringify(parsedValue, null, 2); diff --git a/test/fixtures/typescript-effect-schema/tsconfig.json b/test/fixtures/typescript-effect-schema/tsconfig.json index 3c2a002b..a5befbe0 100644 --- a/test/fixtures/typescript-effect-schema/tsconfig.json +++ b/test/fixtures/typescript-effect-schema/tsconfig.json @@ -2,7 +2,5 @@ "compilerOptions": { "target": "es6" }, - "files": [ - "*.ts" - ] -} \ No newline at end of file + "files": ["*.ts"] +} diff --git a/test/fixtures/typescript-zod/main.ts b/test/fixtures/typescript-zod/main.ts index f7e16738..8c207d96 100644 --- a/test/fixtures/typescript-zod/main.ts +++ b/test/fixtures/typescript-zod/main.ts @@ -2,7 +2,6 @@ import * as TopLevel from "./TopLevel"; import fs from "fs"; import process from "process"; - const sample = process.argv[2]; const json = fs.readFileSync(sample); @@ -10,8 +9,11 @@ const value = JSON.parse(json.toString()); let schema = TopLevel.TopLevelSchema ?? TopLevel.TopLevelElementSchema; if (!schema) { // Sometimes key is prefixed with funPrefixes (e.g. 2df80.json) - Object.keys(TopLevel).some(key => { - if (key.endsWith("TopLevelSchema") || key.endsWith("TopLevelElementSchema")) { + Object.keys(TopLevel).some((key) => { + if ( + key.endsWith("TopLevelSchema") || + key.endsWith("TopLevelElementSchema") + ) { schema = TopLevel[key]; return true; } @@ -24,7 +26,7 @@ if (!schema) { let backToJson: string; if (Array.isArray(value)) { - const parsedValue = value.map(v => schema.parse(v)); + const parsedValue = value.map((v) => schema.parse(v)); backToJson = JSON.stringify(parsedValue, null, 2); } else { const parsedValue = schema.parse(value); diff --git a/test/fixtures/typescript-zod/tsconfig.json b/test/fixtures/typescript-zod/tsconfig.json index 3c2a002b..a5befbe0 100644 --- a/test/fixtures/typescript-zod/tsconfig.json +++ b/test/fixtures/typescript-zod/tsconfig.json @@ -2,7 +2,5 @@ "compilerOptions": { "target": "es6" }, - "files": [ - "*.ts" - ] -} \ No newline at end of file + "files": ["*.ts"] +} diff --git a/test/fixtures/typescript/main.ts b/test/fixtures/typescript/main.ts index 964d25d8..c22518dd 100644 --- a/test/fixtures/typescript/main.ts +++ b/test/fixtures/typescript/main.ts @@ -7,7 +7,7 @@ const process = require("process"); const sample = process.argv[2]; const json = fs.readFileSync(sample); -let value = TopLevel.Convert.toTopLevel(json); -let backToJson = TopLevel.Convert.topLevelToJson(value); +const value = TopLevel.Convert.toTopLevel(json); +const backToJson = TopLevel.Convert.topLevelToJson(value); console.log(backToJson); diff --git a/test/fixtures/typescript/tsconfig.json b/test/fixtures/typescript/tsconfig.json index 3c2a002b..a5befbe0 100644 --- a/test/fixtures/typescript/tsconfig.json +++ b/test/fixtures/typescript/tsconfig.json @@ -2,7 +2,5 @@ "compilerOptions": { "target": "es6" }, - "files": [ - "*.ts" - ] -} \ No newline at end of file + "files": ["*.ts"] +} diff --git a/test/languages.ts b/test/languages.ts index 95d3e3ea..9573f3e5 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -1,10 +1,15 @@ -import { type LanguageName } from "quicktype-core"; +import type { LanguageName } from "quicktype-core"; import * as process from "process"; // @ts-ignore -import { RendererOptions } from "../dist/quicktype-core/Run"; +import type { RendererOptions } from "../dist/quicktype-core/Run"; -const easySampleJSONs = ["bitcoin-block.json", "pokedex.json", "simple-object.json", "getting-started.json"]; +const easySampleJSONs = [ + "bitcoin-block.json", + "pokedex.json", + "simple-object.json", + "getting-started.json", +]; export type LanguageFeature = | "enum" @@ -52,17 +57,26 @@ export const CSharpLanguage: Language = { diffViaSchema: true, skipDiffViaSchema: ["34702.json", "437e7.json"], allowMissingNull: false, - features: ["enum", "union", "no-defaults", "strict-optional", "date-time", "integer-string", "bool-string", "uuid"], + features: [ + "enum", + "union", + "no-defaults", + "strict-optional", + "date-time", + "integer-string", + "bool-string", + "uuid", + ], output: "QuickType.cs", topLevel: "TopLevel", skipJSON: [ "nbl-stats.json", // See issue #823 "empty-enum.json", // https://github.com/JamesNK/Newtonsoft.Json/issues/1687 - "31189.json" // JSON.NET doesn't accept year 0000 as 1BC, though it should + "31189.json", // JSON.NET doesn't accept year 0000 as 1BC, though it should ], skipMiscJSON: false, skipSchema: [ - "top-level-enum.schema" // The code we generate for top-level enums is incompatible with the driver + "top-level-enum.schema", // The code we generate for top-level enums is incompatible with the driver ], rendererOptions: { "check-required": "true" }, quickTestRendererOptions: [ @@ -70,9 +84,9 @@ export const CSharpLanguage: Language = { { "csharp-version": "5" }, { density: "dense" }, { "number-type": "decimal" }, - { "any-type": "dynamic" } + { "any-type": "dynamic" }, ], - sourceFiles: ["src/language/CSharp/index.ts"] + sourceFiles: ["src/language/CSharp/index.ts"], }; export const CSharpLanguageSystemTextJson: Language = { @@ -86,25 +100,34 @@ export const CSharpLanguageSystemTextJson: Language = { diffViaSchema: true, skipDiffViaSchema: ["34702.json", "437e7.json"], allowMissingNull: false, - features: ["enum", "union", "no-defaults", "strict-optional", "date-time", "integer-string", "bool-string", "uuid"], + features: [ + "enum", + "union", + "no-defaults", + "strict-optional", + "date-time", + "integer-string", + "bool-string", + "uuid", + ], output: "QuickType.cs", topLevel: "TopLevel", skipJSON: [ - "31189.json" // .NET doesn't accept year 0000 as 1BC, though it should + "31189.json", // .NET doesn't accept year 0000 as 1BC, though it should ], skipMiscJSON: false, skipSchema: [ - "top-level-enum.schema" // The code we generate for top-level enums is incompatible with the driver + "top-level-enum.schema", // The code we generate for top-level enums is incompatible with the driver ], - rendererOptions: { "check-required": "true", "framework": "SystemTextJson" }, + rendererOptions: { "check-required": "true", framework: "SystemTextJson" }, quickTestRendererOptions: [ { "array-type": "list" }, { "csharp-version": "6" }, { density: "dense" }, { "number-type": "decimal" }, - { "any-type": "dynamic" } + { "any-type": "dynamic" }, ], - sourceFiles: ["src/language/CSharp/index.ts"] + sourceFiles: ["src/language/CSharp/index.ts"], }; export const JavaLanguage: Language = { @@ -122,34 +145,38 @@ export const JavaLanguage: Language = { features: ["enum", "union", "uuid"], output: "src/main/java/io/quicktype/TopLevel.java", topLevel: "TopLevel", - skipJSON: ["identifiers.json", "simple-identifiers.json", "nst-test-suite.json"], + skipJSON: [ + "identifiers.json", + "simple-identifiers.json", + "nst-test-suite.json", + ], skipMiscJSON: false, skipSchema: ["keyword-unions.schema"], // generates classes with names that are case-insensitively equal rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/Java/index.ts"] + sourceFiles: ["src/language/Java/index.ts"], }; export const JavaLanguageWithLegacyDateTime: Language = { ...JavaLanguage, skipSchema: [ ...JavaLanguage.skipSchema, - "date-time.schema" // Expects less strict serialization. + "date-time.schema", // Expects less strict serialization. ], skipJSON: [ ...(JavaLanguage.skipJSON !== undefined ? JavaLanguage.skipJSON : []), "0a358.json", // Expects less strict serialization (optional milliseconds). - "337ed.json" // Expects less strict serialization (optional milliseconds). + "337ed.json", // Expects less strict serialization (optional milliseconds). ], skipMiscJSON: true, // Handles edge cases differently and does not allow optional milliseconds. rendererOptions: { "datetime-provider": "legacy" }, - quickTestRendererOptions: [{ "array-type": "list" }] + quickTestRendererOptions: [{ "array-type": "list" }], }; export const JavaLanguageWithLombok: Language = { ...JavaLanguage, base: "test/fixtures/java-lombok", - quickTestRendererOptions: [{ "array-type": "list", "lombok": "true" }] + quickTestRendererOptions: [{ "array-type": "list", lombok: "true" }], }; export const PythonLanguage: Language = { @@ -169,22 +196,30 @@ export const PythonLanguage: Language = { "7681c.json", "c3303.json", "e8b04.json", - "f6a65.json" + "f6a65.json", ], allowMissingNull: true, - features: ["enum", "union", "no-defaults", "date-time", "integer-string", "bool-string", "uuid"], + features: [ + "enum", + "union", + "no-defaults", + "date-time", + "integer-string", + "bool-string", + "uuid", + ], output: "quicktype.py", topLevel: "TopLevel", skipJSON: [ - "31189.json" // year 0 is out of range + "31189.json", // year 0 is out of range ], skipMiscJSON: false, skipSchema: [ - "keyword-unions.schema" // Requires more than 255 arguments + "keyword-unions.schema", // Requires more than 255 arguments ], rendererOptions: {}, quickTestRendererOptions: [{ "python-version": "3.5" }], - sourceFiles: ["src/language/Python/index.ts"] + sourceFiles: ["src/language/Python/index.ts"], }; export const RustLanguage: Language = { @@ -210,7 +245,7 @@ export const RustLanguage: Language = { "af2d1.json", "c3303.json", "e8b04.json", - "f6a65.json" + "f6a65.json", ], allowMissingNull: false, features: ["enum", "union", "no-defaults"], @@ -224,9 +259,9 @@ export const RustLanguage: Language = { { density: "dense" }, { visibility: "crate" }, { visibility: "private" }, - { visibility: "public" } + { visibility: "public" }, ], - sourceFiles: ["src/language/Rust/index.ts"] + sourceFiles: ["src/language/Rust/index.ts"], }; export const CrystalLanguage: Language = { @@ -253,19 +288,19 @@ export const CrystalLanguage: Language = { "4961a.json", "32431.json", "68c30.json", - "e8b04.json" + "e8b04.json", ], skipSchema: [ // Crystal does not handle enum mapping "enum.schema", // Crystal does not support top-level primitives "top-level-enum.schema", - "keyword-unions.schema" + "keyword-unions.schema", ], skipMiscJSON: false, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Crystal/index.ts"] + sourceFiles: ["src/language/Crystal/index.ts"], }; export const RubyLanguage: Language = { @@ -327,7 +362,7 @@ export const RubyLanguage: Language = { "e53b5.json", "f22f5.json", "f3139.json", - "e8b04.json" + "e8b04.json", ], allowMissingNull: true, features: ["enum", "union", "no-defaults"], @@ -348,16 +383,16 @@ export const RubyLanguage: Language = { "union-constructor-clash.json", "unions.json", "nbl-stats.json", - "kitchen-sink.json" + "kitchen-sink.json", ], skipSchema: [ // We don't generate a convenience method for top-level enums - "top-level-enum.schema" + "top-level-enum.schema", ], skipMiscJSON: false, rendererOptions: {}, quickTestRendererOptions: [["pokedex.json", { namespace: "QuickType" }]], - sourceFiles: ["src/language/ruby/index.ts"] + sourceFiles: ["src/language/ruby/index.ts"], }; export const GoLanguage: Language = { @@ -375,7 +410,7 @@ export const GoLanguage: Language = { "337ed.json", "34702.json", "7eb30.json", - "e8b04.json" + "e8b04.json", ], allowMissingNull: false, features: ["union"], @@ -397,17 +432,17 @@ export const GoLanguage: Language = { "437e7.json", "127a1.json", "26b49.json", - "0cffa.json" + "0cffa.json", ], skipMiscJSON: false, skipSchema: [ // can't differenciate empty array and nothing for optional empty array // (omitempty). - "postman-collection.schema" + "postman-collection.schema", ], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Golang/index.ts"] + sourceFiles: ["src/language/Golang/index.ts"], }; export const CJSONLanguage: Language = { @@ -415,7 +450,8 @@ export const CJSONLanguage: Language = { base: "test/fixtures/cjson", setupCommand: "curl -o cJSON.c https://raw.githubusercontent.com/DaveGamble/cJSON/v1.7.15/cJSON.c && curl -o cJSON.h https://raw.githubusercontent.com/DaveGamble/cJSON/v1.7.15/cJSON.h && curl -o list.h https://raw.githubusercontent.com/joelguittet/c-list/master/include/list.h && curl -o list.c https://raw.githubusercontent.com/joelguittet/c-list/master/src/list.c && curl -o hashtable.h https://raw.githubusercontent.com/joelguittet/c-hashtable/master/include/hashtable.h && curl -o hashtable.c https://raw.githubusercontent.com/joelguittet/c-hashtable/master/src/hashtable.c", - compileCommand: "gcc -O0 -o quicktype -I. cJSON.c hashtable.c list.c main.c -lpthread", + compileCommand: + "gcc -O0 -o quicktype -I. cJSON.c hashtable.c list.c main.c -lpthread", runCommand(sample: string) { return `valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --error-exitcode=1 ./quicktype "${sample}"`; }, @@ -430,10 +466,17 @@ export const CJSONLanguage: Language = { "fcca3.json", "bug427.json", "github-events.json", - "keywords.json" + "keywords.json", ], allowMissingNull: false, - features: ["minmax", "minmaxlength", "pattern", "enum", "union", "no-defaults"], + features: [ + "minmax", + "minmaxlength", + "pattern", + "enum", + "union", + "no-defaults", + ], output: "TopLevel.h", topLevel: "TopLevel", skipJSON: [ @@ -450,7 +493,7 @@ export const CJSONLanguage: Language = { /* Map in Array in TopLevel is not supported (for the current implementation, can be added later, need recursivity) */ "combinations2.json", /* Array in Array in Union is not supported (for the current implementation, can be added later, need recursivity) */ - "combinations4.json" + "combinations4.json", ], skipMiscJSON: false, skipSchema: [ @@ -481,11 +524,11 @@ export const CJSONLanguage: Language = { "optional-any.schema", "required-non-properties.schema", /* Other cases not supported */ - "implicit-class-array-union.schema" + "implicit-class-array-union.schema", ], rendererOptions: {}, quickTestRendererOptions: [{ "source-style": "single-source" }], - sourceFiles: ["src/language/CJSON/index.ts"] + sourceFiles: ["src/language/CJSON/index.ts"], }; export const CPlusPlusLanguage: Language = { @@ -512,10 +555,17 @@ export const CPlusPlusLanguage: Language = { "c3303.json", "e8b04.json", "f6a65.json", - "fcca3.json" + "fcca3.json", ], allowMissingNull: false, - features: ["minmax", "minmaxlength", "pattern", "enum", "union", "no-defaults"], + features: [ + "minmax", + "minmaxlength", + "pattern", + "enum", + "union", + "no-defaults", + ], output: "TopLevel.hpp", topLevel: "TopLevel", skipJSON: [ @@ -528,12 +578,12 @@ export const CPlusPlusLanguage: Language = { "combinations1.json", "combinations2.json", "combinations3.json", - "combinations4.json" + "combinations4.json", ], skipMiscJSON: false, skipSchema: [ // uses too much memory - "keyword-unions.schema" + "keyword-unions.schema", ], rendererOptions: {}, quickTestRendererOptions: [ @@ -542,9 +592,9 @@ export const CPlusPlusLanguage: Language = { { "code-format": "with-struct" }, { wstring: "use-wstring" }, { "const-style": "east-const" }, - { boost: "false" } + { boost: "false" }, ], - sourceFiles: ["src/language/CPlusPlus/index.ts"] + sourceFiles: ["src/language/CPlusPlus/index.ts"], }; export const ElmLanguage: Language = { @@ -584,7 +634,7 @@ export const ElmLanguage: Language = { "be234.json", "c3303.json", "e8b04.json", - "f6a65.json" + "f6a65.json", ], allowMissingNull: false, features: ["enum", "union", "no-defaults"], @@ -600,7 +650,7 @@ export const ElmLanguage: Language = { "bug790.json", "list.json", "nst-test-suite.json", - "keywords.json" // stack overflow + "keywords.json", // stack overflow ], skipMiscJSON: false, skipSchema: [ @@ -612,11 +662,11 @@ export const ElmLanguage: Language = { "postman-collection.schema", // recursion "vega-lite.schema", // recursion "simple-ref.schema", // recursion - "keyword-unions.schema" // can't handle "hasOwnProperty" for some reason + "keyword-unions.schema", // can't handle "hasOwnProperty" for some reason ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/Elm/index.ts"] + sourceFiles: ["src/language/Elm/index.ts"], }; export const SwiftLanguage: Language = { @@ -661,7 +711,7 @@ export const SwiftLanguage: Language = { "f6a65.json", // date-time issues "fcca3.json", "f82d9.json", - "bug863.json" // Unable to resolve reserved keyword use, "description" + "bug863.json", // Unable to resolve reserved keyword use, "description" ], allowMissingNull: true, features: ["enum", "union", "no-defaults", "date-time"], @@ -674,7 +724,7 @@ export const SwiftLanguage: Language = { "blns-object.json", // Doesn't seem to work on Linux, works on MacOS "nst-test-suite.json", - "null-safe.json" + "null-safe.json", ], skipMiscJSON: false, skipSchema: [ @@ -691,7 +741,7 @@ export const SwiftLanguage: Language = { "class-with-additional.schema", "class-map-union.schema", "vega-lite.schema", - "top-level-primitive.schema" + "top-level-primitive.schema", ], rendererOptions: { "support-linux": "true" }, quickTestRendererOptions: [ @@ -702,9 +752,9 @@ export const SwiftLanguage: Language = { { "access-level": "internal" }, { "access-level": "public" }, { protocol: "equatable" }, - ["simple-object.json", { protocol: "hashable" }] + ["simple-object.json", { protocol: "hashable" }], ], - sourceFiles: ["src/language/Swift/index.ts"] + sourceFiles: ["src/language/Swift/index.ts"], }; export const ObjectiveCLanguage: Language = { @@ -736,13 +786,13 @@ export const ObjectiveCLanguage: Language = { // Could not convert JSON to model: Error Domain=JSONSerialization Code=-1 "(null)" UserInfo={exception=-[NSNull countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x7fff807b6ea0} "combinations2.json", "combinations3.json", - "combinations4.json" + "combinations4.json", ], skipMiscJSON: false, skipSchema: [], rendererOptions: { functions: "true" }, quickTestRendererOptions: [], - sourceFiles: ["src/language/Objective-C/index.ts"] + sourceFiles: ["src/language/Objective-C/index.ts"], }; export const TypeScriptLanguage: Language = { @@ -768,14 +818,14 @@ export const TypeScriptLanguage: Language = { "c8c7e.json", "cda6c.json", "e53b5.json", - "e8b04.json" + "e8b04.json", ], allowMissingNull: false, features: ["enum", "union", "no-defaults", "strict-optional", "date-time"], output: "TopLevel.ts", topLevel: "TopLevel", skipJSON: [ - "7681c.json" // year 0 is out of range + "7681c.json", // year 0 is out of range ], skipMiscJSON: false, skipSchema: ["keyword-unions.schema"], // can't handle "constructor" property @@ -788,9 +838,9 @@ export const TypeScriptLanguage: Language = { ["pokedex.json", { "prefer-types": "true" }], { "acronym-style": "pascal" }, { converters: "all-objects" }, - { readonly: "true" } + { readonly: "true" }, ], - sourceFiles: ["src/language/TypeScript/index.ts"] + sourceFiles: ["src/language/TypeScript/index.ts"], }; export const JavaScriptLanguage: Language = { @@ -807,7 +857,7 @@ export const JavaScriptLanguage: Language = { output: "TopLevel.js", topLevel: "TopLevel", skipJSON: [ - "7681c.json" // year 0 is out of range + "7681c.json", // year 0 is out of range ], skipMiscJSON: false, skipSchema: ["keyword-unions.schema"], // can't handle "constructor" property @@ -815,9 +865,9 @@ export const JavaScriptLanguage: Language = { quickTestRendererOptions: [ { "runtime-typecheck": "false" }, { "runtime-typecheck-ignore-unknown-properties": "true" }, - { converters: "top-level" } + { converters: "top-level" }, ], - sourceFiles: ["src/language/JavaScript/index.ts"] + sourceFiles: ["src/language/JavaScript/index.ts"], }; export const JavaScriptPropTypesLanguage: Language = { @@ -839,7 +889,7 @@ export const JavaScriptPropTypesLanguage: Language = { "bug790.json", // renderer does not support recursion "recursive.json", // renderer does not support recursion "spotify-album.json", // renderer does not support recursion - "76ae1.json" // renderer does not support recursion + "76ae1.json", // renderer does not support recursion ], skipSchema: [], skipMiscJSON: false, @@ -847,9 +897,9 @@ export const JavaScriptPropTypesLanguage: Language = { quickTestRendererOptions: [ { "runtime-typecheck": "false" }, { "runtime-typecheck-ignore-unknown-properties": "true" }, - { converters: "top-level" } + { converters: "top-level" }, ], - sourceFiles: ["src/language/JavaScriptPropTypes/index.ts"] + sourceFiles: ["src/language/JavaScriptPropTypes/index.ts"], }; export const FlowLanguage: Language = { @@ -865,20 +915,20 @@ export const FlowLanguage: Language = { output: "TopLevel.js", topLevel: "TopLevel", skipJSON: [ - "7681c.json" // year 0 is out of range + "7681c.json", // year 0 is out of range ], skipMiscJSON: false, skipSchema: [ - "keyword-unions.schema" // can't handle "constructor" property + "keyword-unions.schema", // can't handle "constructor" property ], rendererOptions: { "explicit-unions": "yes" }, quickTestRendererOptions: [ { "runtime-typecheck": "false" }, { "runtime-typecheck-ignore-unknown-properties": "true" }, { "nice-property-names": "true" }, - { "declare-unions": "true" } + { "declare-unions": "true" }, ], - sourceFiles: ["src/language/Flow/index.ts"] + sourceFiles: ["src/language/Flow/index.ts"], }; export const Scala3Language: Language = { @@ -938,7 +988,7 @@ I havea no idea how to encode these tests correctly. "combinations3.json", "combinations4.json", "unions.json", - "nst-test-suite.json" + "nst-test-suite.json", ], skipSchema: [ // 12 skips @@ -953,12 +1003,12 @@ I havea no idea how to encode these tests correctly. "enum.schema", "class-with-additional.schema", "class-map-union.schema", - "keyword-unions.schema" + "keyword-unions.schema", ], skipMiscJSON: false, rendererOptions: { framework: "circe" }, quickTestRendererOptions: [], - sourceFiles: ["src/language/Scala3/index.ts"] + sourceFiles: ["src/language/Scala3/index.ts"], }; export const Smithy4sLanguage: Language = { @@ -1018,13 +1068,13 @@ I havea no idea how to encode these tests correctly. "combinations3.json", "combinations4.json", "unions.json", - "nst-test-suite.json" + "nst-test-suite.json", ], skipSchema: [], skipMiscJSON: false, rendererOptions: { framework: "just-types" }, quickTestRendererOptions: [], - sourceFiles: ["src/language/Smithy4s/index.ts"] + sourceFiles: ["src/language/Smithy4s/index.ts"], }; export const KotlinLanguage: Language = { @@ -1040,7 +1090,7 @@ export const KotlinLanguage: Language = { "keywords.json", // TODO Investigate these "34702.json", - "76ae1.json" + "76ae1.json", ], allowMissingNull: true, features: ["enum", "union", "no-defaults"], @@ -1078,7 +1128,7 @@ export const KotlinLanguage: Language = { // TODO Investigate these "af2d1.json", "32431.json", - "bug427.json" + "bug427.json", ], skipSchema: [ // Very weird - the types are correct, but it can (de)serialize the string, @@ -1104,12 +1154,12 @@ export const KotlinLanguage: Language = { "keyword-unions.schema", // Klaxon does not support top-level primitives "top-level-enum.schema", - "top-level-primitive.schema" + "top-level-primitive.schema", ], skipMiscJSON: false, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Kotlin/index.ts"] + sourceFiles: ["src/language/Kotlin/index.ts"], }; export const KotlinJacksonLanguage: Language = { @@ -1125,7 +1175,7 @@ export const KotlinJacksonLanguage: Language = { "keywords.json", // TODO Investigate these "34702.json", - "76ae1.json" + "76ae1.json", ], allowMissingNull: true, features: ["enum", "union", "no-defaults"], @@ -1162,7 +1212,7 @@ export const KotlinJacksonLanguage: Language = { // TODO Investigate these "af2d1.json", "32431.json", - "bug427.json" + "bug427.json", ], skipSchema: [ // Very weird - the types are correct, but it can (de)serialize the string, @@ -1188,12 +1238,12 @@ export const KotlinJacksonLanguage: Language = { "keyword-unions.schema", // Klaxon does not support top-level primitives "top-level-enum.schema", - "top-level-primitive.schema" + "top-level-primitive.schema", ], skipMiscJSON: false, rendererOptions: { framework: "jackson" }, quickTestRendererOptions: [], - sourceFiles: ["src/language/Kotlin/index.ts"] + sourceFiles: ["src/language/Kotlin/index.ts"], }; export const DartLanguage: Language = { @@ -1223,7 +1273,7 @@ export const DartLanguage: Language = { "us-senators.json", "0a91a.json", "github-events.json", - "keywords.json" + "keywords.json", ], skipSchema: [ "enum-with-null.schema", @@ -1238,12 +1288,12 @@ export const DartLanguage: Language = { "simple-ref.schema", "keyword-unions.schema", "ref-remote.schema", - "uuid.schema" + "uuid.schema", ], skipMiscJSON: true, rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Dart/index.ts"] + sourceFiles: ["src/language/Dart/index.ts"], }; export const PikeLanguage: Language = { @@ -1279,7 +1329,7 @@ export const PikeLanguage: Language = { "d23d5.json", "dc44f.json", "dec3a.json", - "f22f5.json" + "f22f5.json", ], skipMiscJSON: false, skipSchema: [ @@ -1292,11 +1342,11 @@ export const PikeLanguage: Language = { "class-with-additional.schema", "multi-type-enum.schema", "class-map-union.schema", - "implicit-class-array-union.schema" + "implicit-class-array-union.schema", ], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Pike/index.ts"] + sourceFiles: ["src/language/Pike/index.ts"], }; export const HaskellLanguage: Language = { @@ -1323,7 +1373,7 @@ export const HaskellLanguage: Language = { "76ae1.json", "af2d1.json", "be234.json", - "e8b04.json" + "e8b04.json", ], allowMissingNull: false, features: ["enum", "union", "no-defaults"], @@ -1366,7 +1416,7 @@ export const HaskellLanguage: Language = { "recursive.json", "bug427.json", "nst-test-suite.json", - "keywords.json" + "keywords.json", ], skipMiscJSON: false, skipSchema: [ @@ -1381,17 +1431,17 @@ export const HaskellLanguage: Language = { "keyword-unions.schema", "optional-any.schema", "required.schema", - "required-non-properties.schema" + "required-non-properties.schema", ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/Haskell/index.ts"] + sourceFiles: ["src/language/Haskell/index.ts"], }; export const PHPLanguage: Language = { name: "php", base: "test/fixtures/php", - runCommand: sample => `php main.php \"${sample}\"`, + runCommand: (sample) => `php main.php \"${sample}\"`, diffViaSchema: false, skipDiffViaSchema: [], allowMissingNull: true, @@ -1403,7 +1453,7 @@ export const PHPLanguage: Language = { skipSchema: [], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Php/index.ts"] + sourceFiles: ["src/language/Php/index.ts"], }; export const TypeScriptZodLanguage: Language = { @@ -1437,7 +1487,7 @@ export const TypeScriptZodLanguage: Language = { "76ae1.json", "af2d1.json", "be234.json", - "e8b04.json" + "e8b04.json", ], allowMissingNull: false, features: ["enum", "union", "no-defaults", "date-time"], @@ -1502,7 +1552,7 @@ export const TypeScriptZodLanguage: Language = { "keywords.json", "ed095.json", "7681c.json", - "32d5c.json" + "32d5c.json", ], skipMiscJSON: false, skipSchema: [ @@ -1517,11 +1567,11 @@ export const TypeScriptZodLanguage: Language = { "keyword-unions.schema", "optional-any.schema", "required.schema", - "required-non-properties.schema" + "required-non-properties.schema", ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/TypeScriptZod/index.ts"] + sourceFiles: ["src/language/TypeScriptZod/index.ts"], }; export const TypeScriptEffectSchemaLanguage: Language = { @@ -1555,7 +1605,7 @@ export const TypeScriptEffectSchemaLanguage: Language = { "76ae1.json", "af2d1.json", "be234.json", - "e8b04.json" + "e8b04.json", ], allowMissingNull: false, features: ["enum", "union", "no-defaults"], @@ -1618,7 +1668,7 @@ export const TypeScriptEffectSchemaLanguage: Language = { "bug427.json", "nst-test-suite.json", "keywords.json", - "ed095.json" + "ed095.json", ], skipMiscJSON: false, skipSchema: [ @@ -1633,11 +1683,11 @@ export const TypeScriptEffectSchemaLanguage: Language = { "keyword-unions.schema", "optional-any.schema", "required.schema", - "required-non-properties.schema" + "required-non-properties.schema", ], rendererOptions: {}, quickTestRendererOptions: [{ "array-type": "list" }], - sourceFiles: ["src/language/TypeScriptEffectSchema/index.ts"] + sourceFiles: ["src/language/TypeScriptEffectSchema/index.ts"], }; export const ElixirLanguage: Language = { @@ -1671,7 +1721,7 @@ export const ElixirLanguage: Language = { "bug427.json", "keywords.json", "kitchen-sink.json", - "reddit.json" + "reddit.json", ], allowMissingNull: false, features: ["enum", "no-defaults", "strict-optional"], @@ -1679,7 +1729,7 @@ export const ElixirLanguage: Language = { topLevel: "TopLevel", skipJSON: [ // Some field names are too long to be expressed as atoms and some contain invalid characters. - "blns-object.json" + "blns-object.json", ], skipMiscJSON: false, skipSchema: [ @@ -1694,9 +1744,9 @@ export const ElixirLanguage: Language = { // The test incorrectly succeeds due to the emitter being permissive for unions that contain only primitives. A future enhancement // for the Elixir emitter could be a user-controlled 'strict' mode that pattern matches even on unions of only primitive types. - "go-schema-pattern-properties.schema" + "go-schema-pattern-properties.schema", ], rendererOptions: {}, quickTestRendererOptions: [], - sourceFiles: ["src/language/Elixir/index.ts"] + sourceFiles: ["src/language/Elixir/index.ts"], }; diff --git a/test/lib/deepEquals.ts b/test/lib/deepEquals.ts index 0561b76b..eaeb1209 100644 --- a/test/lib/deepEquals.ts +++ b/test/lib/deepEquals.ts @@ -1,6 +1,6 @@ import moment from "moment"; -import { Moment } from "moment"; -import { ComparisonRelaxations } from "../utils"; +import type { Moment } from "moment"; +import type { ComparisonRelaxations } from "../utils"; function pathToString(path: string[]): string { return "." + path.join("."); @@ -37,7 +37,7 @@ export default function deepEquals( y: any, assumeStringsEqual: boolean, relax: ComparisonRelaxations, - path: string[] = [] + path: string[] = [], ): boolean { // remember that NaN === NaN returns false // and isNaN(undefined) returns true @@ -64,23 +64,35 @@ export default function deepEquals( if (assumeStringsEqual || x === y) return true; const [xMoment, isTime] = tryParseMoment(x); const [yMoment] = tryParseMoment(y); - if (xMoment !== undefined && yMoment !== undefined && momentsEqual(xMoment, yMoment, isTime)) { + if ( + xMoment !== undefined && + yMoment !== undefined && + momentsEqual(xMoment, yMoment, isTime) + ) { return true; } console.error( - `Strings not equal at path ${pathToString(path)}: ${JSON.stringify(x)} !== ${JSON.stringify(y)}.` + `Strings not equal at path ${pathToString(path)}: ${JSON.stringify(x)} !== ${JSON.stringify(y)}.`, ); return false; } - if (!!relax.allowStringifiedIntegers && typeof x === "string" && typeof y === "number") { + if ( + !!relax.allowStringifiedIntegers && + typeof x === "string" && + typeof y === "number" + ) { if (x === y.toString()) return true; - console.error(`String and number not equal at path ${pathToString(path)}.`); + console.error( + `String and number not equal at path ${pathToString(path)}.`, + ); return false; } if (x instanceof String && y instanceof String) { if (x.toString() === y.toString()) return true; - console.error(`Number or string not equal at path ${pathToString(path)}.`); + console.error( + `Number or string not equal at path ${pathToString(path)}.`, + ); return false; } @@ -96,7 +108,7 @@ export default function deepEquals( console.error( `Not the same constructor at path ${pathToString(path)}: should be ${x.constructor} but is ${ y.constructor - }.` + }.`, ); return false; } @@ -108,7 +120,9 @@ export default function deepEquals( if (Array.isArray(x)) { if (x.length !== y.length) { - console.error(`Arrays don't have the same length at path ${pathToString(path)}.`); + console.error( + `Arrays don't have the same length at path ${pathToString(path)}.`, + ); return false; } for (let i = 0; i < x.length; i++) { @@ -131,7 +145,9 @@ export default function deepEquals( // so long as they're null. if (xKeys.indexOf(p) < 0) { if (y[p] !== null) { - console.error(`Non-null property ${p} is not expected at path ${pathToString(path)}.`); + console.error( + `Non-null property ${p} is not expected at path ${pathToString(path)}.`, + ); return false; } } @@ -142,7 +158,9 @@ export default function deepEquals( if (!!relax.allowMissingNull && x[p] === null) { continue; } - console.error(`Expected property ${p} not found at path ${pathToString(path)}.`); + console.error( + `Expected property ${p} not found at path ${pathToString(path)}.`, + ); return false; } diff --git a/test/lib/multicore.ts b/test/lib/multicore.ts index 78fe2de6..117f2801 100644 --- a/test/lib/multicore.ts +++ b/test/lib/multicore.ts @@ -19,21 +19,23 @@ function randomPick(arr: T[]): T { function guys(n: number): string { return _.range(n) - .map(_i => randomPick(WORKERS)) + .map((_i) => randomPick(WORKERS)) .join(" "); } -export async function inParallel(args: ParallelArgs) { - let { queue } = args; - let items = queue.map((item, i) => { +export async function inParallel( + args: ParallelArgs, +) { + const { queue } = args; + const items = queue.map((item, i) => { return { item, i }; }); if (cluster.isPrimary) { - let { setup, workers, map } = args; + const { setup, workers, map } = args; await setup(); - cluster.on("message", worker => { + cluster.on("message", (worker) => { const msg = items.pop(); if (msg !== undefined) { worker.send(msg); @@ -57,30 +59,30 @@ export async function inParallel(args: ParallelArgs + _.range(workers).forEach((i) => cluster.fork({ worker: i, // https://github.com/TypeStrong/ts-node/issues/367 - TS_NODE_PROJECT: "test/tsconfig.json" - }) + TS_NODE_PROJECT: "test/tsconfig.json", + }), ); } } else { // Setup a worker - let { map } = args; + const { map } = args; // master sends a { fixtureName, sample } to run process.on("message", async ({ item, i }) => { - (process.send as any)({ - result: await map(item, i) + process.send?.({ + result: await map(item, i), }); }); // Ask master for work - (process.send as any)("ready"); + process.send?.("ready"); } } diff --git a/test/test.ts b/test/test.ts index e51058f7..f6015eaf 100755 --- a/test/test.ts +++ b/test/test.ts @@ -2,12 +2,12 @@ import * as os from "os"; import * as _ from "lodash"; import { inParallel } from "./lib/multicore"; -import { execAsync, Sample } from "./utils"; -import { Fixture, allFixtures } from "./fixtures"; +import { execAsync, type Sample } from "./utils"; +import { type Fixture, allFixtures } from "./fixtures"; import { affectedFixtures, divideParallelJobs } from "./buildkite"; const exit = require("exit"); -const CPUs = parseInt(process.env.CPUs || "0", 10) || os.cpus().length; +const CPUs = Number.parseInt(process.env.CPUs || "0", 10) || os.cpus().length; ////////////////////////////////////// // Test driver @@ -20,24 +20,36 @@ async function main(sources: string[]) { const fixturesFromCmdline = process.env.FIXTURE; if (fixturesFromCmdline) { const fixtureNames = fixturesFromCmdline.split(","); - fixtures = _.filter(fixtures, fixture => _.some(fixtureNames, name => fixture.runForName(name))); + fixtures = _.filter(fixtures, (fixture) => + _.some(fixtureNames, (name) => fixture.runForName(name)), + ); } if (allFixtures.length !== fixtures.length) { - console.error(`* Running a subset of fixtures: ${fixtures.map(f => f.name).join(", ")}`); + console.error( + `* Running a subset of fixtures: ${fixtures.map((f) => f.name).join(", ")}`, + ); } // Get an array of all { sample, fixtureName } objects we'll run. // We can't just put the fixture in there because these WorkItems // will be sent in a message, removing all code. - const samples = _.map(fixtures, fixture => ({ + const samples = _.map(fixtures, (fixture) => ({ fixtureName: fixture.name, - samples: fixture.getSamples(sources) + samples: fixture.getSamples(sources), })); - const priority = _.flatMap(samples, x => - _.map(x.samples.priority, s => ({ fixtureName: x.fixtureName, sample: s })) + const priority = _.flatMap(samples, (x) => + _.map(x.samples.priority, (s) => ({ + fixtureName: x.fixtureName, + sample: s, + })), + ); + const others = _.flatMap(samples, (x) => + _.map(x.samples.others, (s) => ({ + fixtureName: x.fixtureName, + sample: s, + })), ); - const others = _.flatMap(samples, x => _.map(x.samples.others, s => ({ fixtureName: x.fixtureName, sample: s }))); const tests = divideParallelJobs(_.concat(priority, others)); @@ -46,7 +58,9 @@ async function main(sources: string[]) { workers: CPUs, setup: async () => { - console.error(`* Running ${tests.length} tests between ${fixtures.length} fixtures`); + console.error( + `* Running ${tests.length} tests between ${fixtures.length} fixtures`, + ); for (const fixture of fixtures) { await execAsync(`rm -rf test/runs`); @@ -57,19 +71,19 @@ async function main(sources: string[]) { }, map: async ({ sample, fixtureName }: WorkItem, index) => { - let fixture = _.find(fixtures, { name: fixtureName }) as Fixture; + const fixture = _.find(fixtures, { name: fixtureName }) as Fixture; try { await fixture.runWithSample(sample, index, tests.length); } catch (e) { console.trace(e); exit(1); } - } + }, }); } // skip 2 `node` args -main(process.argv.slice(2)).catch(reason => { +main(process.argv.slice(2)).catch((reason) => { console.error(reason); process.exit(1); }); diff --git a/test/utils.ts b/test/utils.ts index b53715d2..b532a2e8 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,16 +1,19 @@ -import * as fs from "fs"; -import * as path from "path"; +import * as fs from "node:fs"; +import * as path from "node:path"; import * as _ from "lodash"; import * as shell from "shelljs"; -import { main as quicktype_, CLIOptions } from "../src"; -import { RendererOptions } from "quicktype-core"; -import * as languages from "./languages"; +import { main as quicktype_, type CLIOptions } from "../src"; +import type { RendererOptions } from "quicktype-core"; +import type * as languages from "./languages"; import deepEquals from "./lib/deepEquals"; import chalk from "chalk"; -const strictDeepEquals: (x: any, y: any) => boolean = require("deep-equal"); +const strictDeepEquals: ( + x: unknown, + y: unknown, +) => boolean = require("deep-equal"); const DEBUG = process.env.DEBUG !== undefined; const ASSUME_STRINGS_EQUAL = process.env.ASSUME_STRINGS_EQUAL !== undefined; @@ -22,7 +25,7 @@ export function debug(x: T): T { return x; } -export function failWith(message: string, obj: { [key: string]: any }): never { +export function failWith(message: string, obj: Record): never { obj.cwd = process.cwd(); console.error(chalk.red(message)); console.error(chalk.red(JSON.stringify(obj, null, " "))); @@ -44,24 +47,25 @@ export function callAndExpectFailure(message: string, f: () => T): void { } catch { return; } - return failWith(message, { result }); + + failWith(message, { result }); } export function exec( s: string, env: NodeJS.ProcessEnv | undefined, - printFailure = true + printFailure = true, ): { stdout: string; code: number } { debug(s); if (env === undefined) { env = process.env; } - const result = shell.exec(s, { silent: !DEBUG, env }) as any; + const result = shell.exec(s, { silent: !DEBUG, env }); if (result.code !== 0) { const failureObj = { command: s, - code: result.code + code: result.code, }; if (!printFailure) { throw failureObj; @@ -74,7 +78,10 @@ export function exec( return result; } -export function execAsync(s: string, opts: { silent: boolean } = { silent: !DEBUG }) { +export function execAsync( + s: string, + opts: { silent: boolean } = { silent: !DEBUG }, +) { return new Promise<{ stdout: string; code: number }>((resolve, reject) => { debug(s); shell.exec(s, opts, (code, stdout, stderr) => { @@ -89,9 +96,9 @@ export function execAsync(s: string, opts: { silent: boolean } = { silent: !DEBU } async function time(work: () => Promise): Promise<[T, number]> { - let start = +new Date(); - let result = await work(); - let end = +new Date(); + const start = +new Date(); + const result = await work(); + const end = +new Date(); return [result, end - start]; } @@ -99,7 +106,9 @@ async function time(work: () => Promise): Promise<[T, number]> { export function mkdirs(dir: string): void { const components = dir.split(path.sep); if (components.length === 0) { - throw new Error("mkdirs must be called with at least one path component"); + throw new Error( + "mkdirs must be called with at least one path component", + ); } let soFar: string; if (components[0].length === 0) { @@ -132,7 +141,7 @@ export async function quicktypeForLanguage( sourceLanguage: string, alphabetizeProperties: boolean, additionalRendererOptions: RendererOptions, - graphqlSchema?: string + graphqlSchema?: string, ) { try { await quicktype({ @@ -143,12 +152,16 @@ export async function quicktypeForLanguage( graphqlSchema, topLevel: language.topLevel, alphabetizeProperties, - rendererOptions: _.merge({}, language.rendererOptions, additionalRendererOptions), + rendererOptions: _.merge( + {}, + language.rendererOptions, + additionalRendererOptions, + ), quiet: true, telemetry: "disable", // GraphQL input can leave unreachable types in the graph, which means // their provenance won't be propagated. It does that for non-nullables. - debug: graphqlSchema === undefined ? "provenance" : undefined + debug: graphqlSchema === undefined ? "provenance" : undefined, }); } catch (e) { failWith("quicktype threw an exception", { @@ -157,13 +170,13 @@ export async function quicktypeForLanguage( sourceFile, sourceLanguage, graphqlSchema, - additionalRendererOptions + additionalRendererOptions, }); } } export async function inDir(dir: string, work: () => Promise) { - let origin = process.cwd(); + const origin = process.cwd(); debug(`cd ${dir}`); process.chdir(dir); @@ -183,28 +196,33 @@ export interface Sample { } export function samplesFromPaths(paths: string[]): Sample[] { - return paths.map(p => ({ path: p, additionalRendererOptions: {}, saveOutput: true })); + return paths.map((p) => ({ + path: p, + additionalRendererOptions: {}, + saveOutput: true, + })); } export function samplesFromSources( sources: string[], prioritySamples: string[], miscSamples: string[], - extension: string + extension: string, ): { priority: Sample[]; others: Sample[] } { if (sources.length === 0) { return { priority: samplesFromPaths(prioritySamples), - others: samplesFromPaths(miscSamples) + others: samplesFromPaths(miscSamples), }; - } else if (sources.length === 1 && fs.lstatSync(sources[0]).isDirectory()) { + } + if (sources.length === 1 && fs.lstatSync(sources[0]).isDirectory()) { return { priority: samplesFromPaths(testsInDir(sources[0], extension)), - others: [] + others: [], }; - } else { - return { priority: samplesFromPaths(sources), others: [] }; } + + return { priority: samplesFromPaths(sources), others: [] }; } export type ComparisonRelaxations = { @@ -212,7 +230,9 @@ export type ComparisonRelaxations = { allowStringifiedIntegers?: boolean; }; -export type FileOrCommand = { file: string } | { command: string; env: NodeJS.ProcessEnv }; +export type FileOrCommand = + | { file: string } + | { command: string; env: NodeJS.ProcessEnv }; function fileOrCommandIsFile(foc: FileOrCommand): foc is { file: string } { return "file" in foc && foc.file !== undefined; @@ -231,24 +251,34 @@ export function compareJsonFileToJson(args: ComparisonArgs) { const { given } = args; const jsonString = fileOrCommandIsFile(given) - ? callAndReportFailure("Could not read JSON output file", () => fs.readFileSync(given.file, "utf8")) - : callAndReportFailure("Could not run command for JSON output", () => exec(given.command, given.env).stdout); + ? callAndReportFailure("Could not read JSON output file", () => + fs.readFileSync(given.file, "utf8"), + ) + : callAndReportFailure( + "Could not run command for JSON output", + () => exec(given.command, given.env).stdout, + ); - const givenJSON = callAndReportFailure("Could not parse output JSON", () => JSON.parse(jsonString)); - const expectedJSON = callAndReportFailure("Could not read or parse expected JSON file", () => - JSON.parse(fs.readFileSync(expectedFile, "utf8")) + const givenJSON = callAndReportFailure("Could not parse output JSON", () => + JSON.parse(jsonString), + ); + const expectedJSON = callAndReportFailure( + "Could not read or parse expected JSON file", + () => JSON.parse(fs.readFileSync(expectedFile, "utf8")), ); - let jsonAreEqual = strict - ? callAndReportFailure("Failed to strictly compare objects", () => strictDeepEquals(givenJSON, expectedJSON)) + const jsonAreEqual = strict + ? callAndReportFailure("Failed to strictly compare objects", () => + strictDeepEquals(givenJSON, expectedJSON), + ) : callAndReportFailure("Failed to compare objects.", () => - deepEquals(expectedJSON, givenJSON, ASSUME_STRINGS_EQUAL, args) + deepEquals(expectedJSON, givenJSON, ASSUME_STRINGS_EQUAL, args), ); if (!jsonAreEqual) { failWith("Error: Output is not equivalent to input.", { expectedFile, - given + given, }); } }