diff --git a/.gitignore b/.gitignore index d0e387936b6..68310b137ca 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,9 @@ packages/web-features/index.d.ts packages/**/LICENSE.txt packages/web-features/data.json packages/web-features/data.schema.json -packages/web-features/types.ts +packages/web-features/types* +packages/web-features/index.js data.extended.json -index.js # Ignore files created & used by pages & 11ty /_site/** diff --git a/.prettierignore b/.prettierignore index 743a54d17e2..eb97a6eba00 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,7 +2,6 @@ /**/*.dist /**/dist - # Exclude the website includes since these are typically fragments, or include # things that makes Prettier unhappy. /gh-pages/src/_includes/** @@ -11,14 +10,12 @@ # TODO: Format all these files README.md index.ts -types.ts 2022-backgrounder.md towards-features.md /.github/** /docs !/docs/publishing.md /features/draft -/schemas /scripts/caniuse.ts /scripts/schema.ts /scripts/specs.ts diff --git a/features/conic-gradients.yml b/features/conic-gradients.yml index 296df0f44ff..bbe65dfd98e 100644 --- a/features/conic-gradients.yml +++ b/features/conic-gradients.yml @@ -8,4 +8,5 @@ status: compat_features: - css.types.gradient.conic-gradient - css.types.gradient.conic-gradient.doubleposition + - css.types.gradient.conic-gradient.single_color_stop - css.types.gradient.repeating-conic-gradient diff --git a/features/conic-gradients.yml.dist b/features/conic-gradients.yml.dist index 9b55cfcd57f..ff1a7cb8638 100644 --- a/features/conic-gradients.yml.dist +++ b/features/conic-gradients.yml.dist @@ -41,3 +41,15 @@ compat_features: # safari: "12.1" # safari_ios: "12.2" - css.types.gradient.conic-gradient.doubleposition + + # baseline: low + # baseline_low_date: 2025-04-04 + # support: + # chrome: "135" + # chrome_android: "135" + # edge: "135" + # firefox: "136" + # firefox_android: "136" + # safari: "18.4" + # safari_ios: "18.4" + - css.types.gradient.conic-gradient.single_color_stop diff --git a/features/gradients.yml b/features/gradients.yml index fe513c4390c..e95ec8fb792 100644 --- a/features/gradients.yml +++ b/features/gradients.yml @@ -16,18 +16,22 @@ compat_features: - css.types.gradient.linear-gradient.interpolation_hints - css.types.gradient.linear-gradient.premultiplied_gradients - css.types.gradient.linear-gradient.to + - css.types.gradient.linear-gradient.single_color_stop - css.types.gradient.linear-gradient.unitless_0_angle - css.types.gradient.repeating-linear-gradient - css.types.gradient.repeating-linear-gradient.doubleposition - css.types.gradient.repeating-linear-gradient.interpolation_hints - css.types.gradient.repeating-linear-gradient.to + - css.types.gradient.repeating-linear-gradient.single_color_stop - css.types.gradient.repeating-linear-gradient.unitless_0_angle - css.types.gradient.radial-gradient - css.types.gradient.radial-gradient.at - css.types.gradient.radial-gradient.doubleposition - css.types.gradient.radial-gradient.interpolation_hints - css.types.gradient.radial-gradient.premultiplied_gradients + - css.types.gradient.radial-gradient.single_color_stop - css.types.gradient.repeating-radial-gradient - css.types.gradient.repeating-radial-gradient.at - css.types.gradient.repeating-radial-gradient.doubleposition - css.types.gradient.repeating-radial-gradient.interpolation_hints + - css.types.gradient.repeating-radial-gradient.single_color_stop diff --git a/features/gradients.yml.dist b/features/gradients.yml.dist index f5ac728b631..625d60b9b77 100644 --- a/features/gradients.yml.dist +++ b/features/gradients.yml.dist @@ -145,3 +145,18 @@ compat_features: # safari_ios: "15" - css.types.gradient.linear-gradient.premultiplied_gradients - css.types.gradient.radial-gradient.premultiplied_gradients + + # baseline: low + # baseline_low_date: 2025-04-04 + # support: + # chrome: "135" + # chrome_android: "135" + # edge: "135" + # firefox: "136" + # firefox_android: "136" + # safari: "18.4" + # safari_ios: "18.4" + - css.types.gradient.linear-gradient.single_color_stop + - css.types.gradient.radial-gradient.single_color_stop + - css.types.gradient.repeating-linear-gradient.single_color_stop + - css.types.gradient.repeating-radial-gradient.single_color_stop diff --git a/features/numeric-separators.yml b/features/numeric-separators.yml new file mode 100644 index 00000000000..85500442056 --- /dev/null +++ b/features/numeric-separators.yml @@ -0,0 +1,6 @@ +name: Numeric separators +description: To improve readability for numeric literals, underscores (`_`) can be used as separators. For example, `1_050.95` is equivalent to `1050.95`. +spec: https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#prod-NumericLiteralSeparator +group: javascript +compat_features: + - javascript.grammar.numeric_separators diff --git a/features/numeric-separators.yml.dist b/features/numeric-separators.yml.dist new file mode 100644 index 00000000000..996e1916346 --- /dev/null +++ b/features/numeric-separators.yml.dist @@ -0,0 +1,17 @@ +# Generated from: numeric-separators.yml +# Do not edit this file by hand. Edit the source file instead! + +status: + baseline: high + baseline_low_date: 2020-07-28 + baseline_high_date: 2023-01-28 + support: + chrome: "75" + chrome_android: "75" + edge: "79" + firefox: "70" + firefox_android: "79" + safari: "13" + safari_ios: "13" +compat_features: + - javascript.grammar.numeric_separators diff --git a/features/numeric-seperators.yml b/features/numeric-seperators.yml index 85500442056..04c6806c7fd 100644 --- a/features/numeric-seperators.yml +++ b/features/numeric-seperators.yml @@ -1,6 +1,2 @@ -name: Numeric separators -description: To improve readability for numeric literals, underscores (`_`) can be used as separators. For example, `1_050.95` is equivalent to `1050.95`. -spec: https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#prod-NumericLiteralSeparator -group: javascript -compat_features: - - javascript.grammar.numeric_separators +kind: moved +redirect_target: numeric-separators diff --git a/features/numeric-seperators.yml.dist b/features/numeric-seperators.yml.dist index eaa3c384275..9bda2b05ad1 100644 --- a/features/numeric-seperators.yml.dist +++ b/features/numeric-seperators.yml.dist @@ -1,17 +1,6 @@ # Generated from: numeric-seperators.yml -# Do not edit this file by hand. Edit the source file instead! +# This file intentionally left blank. +# Do not edit this file. +# The data for this feature has moved to numeric-separators.yml -status: - baseline: high - baseline_low_date: 2020-07-28 - baseline_high_date: 2023-01-28 - support: - chrome: "75" - chrome_android: "75" - edge: "79" - firefox: "70" - firefox_android: "79" - safari: "13" - safari_ios: "13" -compat_features: - - javascript.grammar.numeric_separators +{} diff --git a/features/single-color-gradients.yml b/features/single-color-gradients.yml index b8e1a4789ba..5d1e93a8ee5 100644 --- a/features/single-color-gradients.yml +++ b/features/single-color-gradients.yml @@ -1,11 +1,4 @@ -name: Single color stop gradients -description: A single color stop can be provided to the `linear-gradient()`, `radial-gradient()`, and `conic-gradient()` CSS functions, and their repeating counterparts, to create a solid color background. -spec: https://drafts.csswg.org/css-images-4/#color-stop-syntax -group: gradients -compat_features: - - css.types.gradient.conic-gradient.single_color_stop - - css.types.gradient.linear-gradient.single_color_stop - - css.types.gradient.radial-gradient.single_color_stop - - css.types.gradient.repeating-conic-gradient.single_color_stop - - css.types.gradient.repeating-linear-gradient.single_color_stop - - css.types.gradient.repeating-radial-gradient.single_color_stop +kind: split +redirect_targets: + - gradients + - conic-gradients diff --git a/features/single-color-gradients.yml.dist b/features/single-color-gradients.yml.dist index 38d174ab005..e7dfa57a3c0 100644 --- a/features/single-color-gradients.yml.dist +++ b/features/single-color-gradients.yml.dist @@ -1,21 +1,8 @@ # Generated from: single-color-gradients.yml -# Do not edit this file by hand. Edit the source file instead! +# This file intentionally left blank. +# Do not edit this file. +# The data for this feature has moved to: +# - gradients.yml +# - conic-gradients.yml -status: - baseline: low - baseline_low_date: 2025-04-04 - support: - chrome: "135" - chrome_android: "135" - edge: "135" - firefox: "136" - firefox_android: "136" - safari: "18.4" - safari_ios: "18.4" -compat_features: - - css.types.gradient.conic-gradient.single_color_stop - - css.types.gradient.linear-gradient.single_color_stop - - css.types.gradient.radial-gradient.single_color_stop - - css.types.gradient.repeating-conic-gradient.single_color_stop - - css.types.gradient.repeating-linear-gradient.single_color_stop - - css.types.gradient.repeating-radial-gradient.single_color_stop +{} diff --git a/index.ts b/index.ts index f9193492782..dd832d3c890 100644 --- a/index.ts +++ b/index.ts @@ -4,7 +4,7 @@ import path from 'path'; import { Temporal } from '@js-temporal/polyfill'; import { fdir } from 'fdir'; import YAML from 'yaml'; -import { FeatureData, GroupData, SnapshotData, WebFeaturesData } from './types'; +import { GroupData, SnapshotData, WebFeaturesData } from './types'; import { toString as hastTreeToString } from 'hast-util-to-string'; import rehypeStringify from 'rehype-stringify'; @@ -14,6 +14,7 @@ import { unified } from 'unified'; import { BASELINE_LOW_TO_HIGH_DURATION, coreBrowserSet, parseRangedDateString } from 'compute-baseline'; import { Compat } from 'compute-baseline/browser-compat-data'; +import { isMoved, isSplit } from './type-guards'; // The longest name allowed, to allow for compact display. const nameMaxLength = 80; @@ -118,7 +119,7 @@ function convertMarkdown(markdown: string) { // Map from BCD keys/paths to web-features identifiers. const bcdToFeatureId: Map = new Map(); -const features: { [key: string]: FeatureData } = {}; +const features: WebFeaturesData["features"] = {}; for (const [key, data] of yamlEntries('features')) { // Draft features reserve an identifier but aren't complete yet. Skip them. if (data[draft]) { @@ -128,6 +129,11 @@ for (const [key, data] of yamlEntries('features')) { continue; } + // Attach `kind: feature` to ordinary features + if (!isMoved(data) && !isSplit(data)) { + data.kind = "feature"; + } + // Convert markdown to text+HTML. if (data.description) { const { text, html } = convertMarkdown(data.description); @@ -183,12 +189,37 @@ for (const [key, data] of yamlEntries('features')) { features[key] = data; } -// Assert that discouraged feature's alternatives are valid -for (const [id, feature] of Object.entries(features)) { - for (const alternative of feature.discouraged?.alternatives ?? []) { - if (!(alternative in features)) { - throw new Error(`${id}'s alternative "${alternative}" is not a valid feature ID`); +// Assert that feature references are valid + +function assertValidReference(sourceID: string, targetID: string): void { + if (targetID in features) { + if (isMoved(features[targetID]) || isSplit(features[targetID])) { + throw new Error(`${sourceID} references a redirect "${targetID}" instead of an ordinary feature ID`); } + return; + } + throw new Error(`${sourceID}'s reference to "${targetID}" is not a valid feature ID`); +} + +for (const [id, feature] of Object.entries(features)) { + const { kind } = feature; + switch (kind) { + case "feature": + for (const alternative of feature.discouraged?.alternatives ?? []) { + assertValidReference(id, alternative); + } + break; + case "moved": + assertValidReference(id, feature.redirect_target); + break; + case "split": + for (const target of feature.redirect_targets) { + assertValidReference(id, target); + } + break; + default: + kind satisfies never; + throw new Error(`Unhandled feature kind ${kind}}`); } } diff --git a/package-lock.json b/package-lock.json index 2614868d2b1..12ef58204f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "fdir": "^6.4.6", "hast-util-to-string": "^3.0.1", "prettier": "^3.6.2", + "quicktype": "^23.2.5", "rehype-stringify": "^10.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", @@ -61,6 +62,30 @@ "node": ">=0.1.90" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@dabh/diagnostics": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", @@ -647,6 +672,13 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@glideapps/ts-necessities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.4.0.tgz", + "integrity": "sha512-mDC+qosuNa4lxR3ioMBb6CD0XLRsQBplU+zRPUYiMLXKeVPZ6UYphdNG/EGReig0YyfnVlBKZEXl1wzTotYmPA==", + "dev": true, + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -796,6 +828,176 @@ "node": ">=12" } }, + "node_modules/@mark.probst/typescript-json-schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@mark.probst/typescript-json-schema/-/typescript-json-schema-0.55.0.tgz", + "integrity": "sha512-jI48mSnRgFQxXiE/UTUCVCpX8lK3wCFKLF1Ss2aEreboKNuLQGt3e0/YFqWVHe/WENxOaqiJvwOz+L/SrN2+qQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/node": "^16.9.2", + "glob": "^7.1.7", + "path-equal": "^1.1.2", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "yargs": "^17.1.1" + }, + "bin": { + "typescript-json-schema": "bin/typescript-json-schema" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/@types/node": { + "version": "16.18.126", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", + "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@mark.probst/typescript-json-schema/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/@mdn/browser-compat-data": { "version": "6.0.31", "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-6.0.31.tgz", @@ -1004,6 +1206,34 @@ "node": ">=14" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/caniuse-lite": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/caniuse-lite/-/caniuse-lite-1.0.5.tgz", @@ -1379,12 +1609,24 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1402,6 +1644,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -1445,12 +1700,29 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "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/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -1482,6 +1754,27 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", @@ -1499,7 +1792,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1518,12 +1810,44 @@ "node": ">=8" } }, + "node_modules/browser-or-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-3.0.0.tgz", + "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", + "dev": true, + "license": "MIT" + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/c8": { "version": "10.1.3", "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", @@ -1754,6 +2078,22 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -1916,6 +2256,13 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -1989,6 +2336,58 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", + "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^4.1.0", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", + "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, "node_modules/commander": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", @@ -2011,8 +2410,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/convert-source-map": { "version": "2.0.0", @@ -2020,6 +2418,23 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2510,6 +2925,26 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2653,6 +3088,19 @@ "node": ">=8" } }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2721,6 +3169,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2839,6 +3294,17 @@ "dev": true, "license": "MIT" }, + "node_modules/graphql": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.11.7.tgz", + "integrity": "sha512-x7uDjyz8Jx+QPbpCFCMQ8lltnQa4p4vSYHx6ADe8rVYRTdsyhCJbvSty5DAsLVmU6cGakl+r8HQYolKHxk/tiw==", + "deprecated": "No longer supported; please update to a newer version. Details: https://github.com/graphql/graphql-js#version-support", + "dev": true, + "license": "MIT", + "dependencies": { + "iterall": "1.1.3" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2965,6 +3431,27 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3002,6 +3489,18 @@ "node": ">=0.8.19" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3090,6 +3589,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3132,6 +3638,13 @@ "node": ">=8" } }, + "node_modules/iterall": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz", + "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==", + "dev": true, + "license": "MIT" + }, "node_modules/jackspeak": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", @@ -3412,6 +3925,13 @@ "node": ">=4" } }, + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3506,6 +4026,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3582,6 +4116,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/mdast-util-from-markdown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", @@ -4124,7 +4665,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4401,6 +4941,16 @@ "node": ">=12" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4413,6 +4963,27 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4434,6 +5005,16 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/one-time": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", @@ -4497,6 +5078,13 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4559,6 +5147,13 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/path-equal": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", + "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4568,6 +5163,16 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -4622,6 +5227,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4693,6 +5308,16 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -4734,6 +5359,145 @@ ], "license": "MIT" }, + "node_modules/quicktype": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/quicktype/-/quicktype-23.2.6.tgz", + "integrity": "sha512-rlD1jF71bOmDn6SQ/ToLuuRkMQ7maxo5oVTn5dPCl11ymqoJCFCvl7FzRfh+fkDFmWt2etl+JiIEdWImLxferA==", + "dev": true, + "license": "Apache-2.0", + "workspaces": [ + "./packages/quicktype-core", + "./packages/quicktype-graphql-input", + "./packages/quicktype-typescript-input", + "./packages/quicktype-vscode" + ], + "dependencies": { + "@glideapps/ts-necessities": "^2.2.3", + "chalk": "^4.1.2", + "collection-utils": "^1.0.1", + "command-line-args": "^5.2.1", + "command-line-usage": "^7.0.1", + "cross-fetch": "^4.0.0", + "graphql": "^0.11.7", + "lodash": "^4.17.21", + "moment": "^2.30.1", + "quicktype-core": "23.2.6", + "quicktype-graphql-input": "23.2.6", + "quicktype-typescript-input": "23.2.6", + "readable-stream": "^4.5.2", + "stream-json": "1.8.0", + "string-to-stream": "^3.0.1", + "typescript": "~5.8.3" + }, + "bin": { + "quicktype": "dist/index.js" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/quicktype-core": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-23.2.6.tgz", + "integrity": "sha512-asfeSv7BKBNVb9WiYhFRBvBZHcRutPRBwJMxW0pefluK4kkKu4lv0IvZBwFKvw2XygLcL1Rl90zxWDHYgkwCmA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@glideapps/ts-necessities": "2.2.3", + "browser-or-node": "^3.0.0", + "collection-utils": "^1.0.1", + "cross-fetch": "^4.0.0", + "is-url": "^1.2.4", + "js-base64": "^3.7.7", + "lodash": "^4.17.21", + "pako": "^1.0.6", + "pluralize": "^8.0.0", + "readable-stream": "4.5.2", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^2.4.1" + } + }, + "node_modules/quicktype-core/node_modules/@glideapps/ts-necessities": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.2.3.tgz", + "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/quicktype-core/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/quicktype-graphql-input": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/quicktype-graphql-input/-/quicktype-graphql-input-23.2.6.tgz", + "integrity": "sha512-jHQ8XrEaccZnWA7h/xqUQhfl+0mR5o91T6k3I4QhlnZSLdVnbycrMq4FHa9EaIFcai783JKwSUl1+koAdJq4pg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "collection-utils": "^1.0.1", + "graphql": "^0.11.7", + "quicktype-core": "23.2.6" + } + }, + "node_modules/quicktype-typescript-input": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/quicktype-typescript-input/-/quicktype-typescript-input-23.2.6.tgz", + "integrity": "sha512-dCNMxR+7PGs9/9Tsth9H6LOQV1G+Tv4sUGT8ZUfDRJ5Hq371qOYLma5BnLX6VxkPu8JT7mAMpQ9VFlxstX6Qaw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@mark.probst/typescript-json-schema": "0.55.0", + "quicktype-core": "23.2.6", + "typescript": "4.9.5" + } + }, + "node_modules/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==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/quicktype/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -5007,6 +5771,23 @@ "node": "*" } }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.8.0.tgz", + "integrity": "sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -5016,6 +5797,16 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-to-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-3.0.1.tgz", + "integrity": "sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -5150,6 +5941,30 @@ "node": ">=8" } }, + "node_modules/table-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-back": "^6.2.2", + "wordwrapjs": "^5.1.0" + }, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, "node_modules/test-exclude": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", @@ -5251,6 +6066,13 @@ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "dev": true }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "dev": true, + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5264,6 +6086,13 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -5328,6 +6157,60 @@ "node": ">=18.0.0" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -5403,6 +6286,16 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/undici": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.10.0.tgz", @@ -5418,6 +6311,35 @@ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "dev": true, + "license": "MIT" + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -5521,12 +6443,26 @@ "punycode": "^2.1.0" } }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "dev": true, + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -5576,6 +6512,13 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -5597,6 +6540,17 @@ "node": ">=18" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5658,6 +6612,23 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wordwrapjs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", + "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, "node_modules/workerpool": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.2.tgz", @@ -5752,6 +6723,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -5846,6 +6824,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 579df360b3a..e0052bd9ee4 100644 --- a/package.json +++ b/package.json @@ -23,17 +23,17 @@ "undist": "tsx scripts/undist.ts", "feature-init": "tsx scripts/feature-init.ts", "format": "npx prettier --write .", - "schema:write": "npm run schema -- --out ./schemas/data.schema.json", - "schema": "ts-json-schema-generator --tsconfig ./tsconfig.json --path ./types.ts --type=WebFeaturesData", + "schematypes": "sh -c \"npx quicktype --lang='typescript' --src-lang schema --src ./schemas/data.schema.json --just-types --prefer-unions --prefer-const-values --top-level=WebFeaturesData | prettier --stdin-filepath ./types.quicktype.ts\"", + "schematypes:write": "npm run --silent schematypes > ./types.quicktype.ts", "test:caniuse": "tsx scripts/caniuse.ts", "test:coverage": "npm run --workspaces test:coverage", "test:dist": "tsx scripts/dist.ts --check", "test:format": "prettier --check .", "test:lint": "npx eslint .", - "test:schema": "tsx scripts/schema.ts", + "test:schematypes": "tsx scripts/schema.ts", "test:specs": "tsx scripts/specs.ts", "test:types": "npm run --workspaces test:types && tsc", - "test": "npm run test:caniuse -- --quiet && npm run test:schema && npm run test:specs && npm run test:types && npm run test:format && npm run test:dist && npm run test --workspaces && npm run test:lint", + "test": "npm run test:caniuse -- --quiet && npm run test:schematypes && npm run test:specs && npm run test:types && npm run test:format && npm run test:dist && npm run test --workspaces && npm run test:lint", "update-drafts": "tsx scripts/update-drafts.ts", "remove-tagged-compat-features": "tsx scripts/remove-tagged-compat-features.ts && npm run format" }, @@ -53,6 +53,7 @@ "fdir": "^6.4.6", "hast-util-to-string": "^3.0.1", "prettier": "^3.6.2", + "quicktype": "^23.2.5", "rehype-stringify": "^10.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", diff --git a/packages/web-features/package.json b/packages/web-features/package.json index 32edd6ce8d4..304b2c2cb1d 100644 --- a/packages/web-features/package.json +++ b/packages/web-features/package.json @@ -18,12 +18,14 @@ "types": "./index.d.ts", "files": [ "index.d.ts", + "types.d.ts", + "types.quicktype.d.ts", "index.js", "data.json", "data.schema.json" ], "scripts": { - "prepare": "tsc && rm types.js && tsup ./index.ts --dts-only --format=esm --out-dir=." + "prepare": "tsc && rm types.js && rm types.quicktype.js" }, "devDependencies": { "@types/node": "^20.19.8", diff --git a/packages/web-features/tsconfig.json b/packages/web-features/tsconfig.json index 216634c4164..e483fa95943 100644 --- a/packages/web-features/tsconfig.json +++ b/packages/web-features/tsconfig.json @@ -3,6 +3,7 @@ "target": "ES2016", "module": "ESNext", "moduleResolution": "Bundler", - "typeRoots": ["./node_modules/@types"] + "typeRoots": ["./node_modules/@types"], + "declaration": true } } diff --git a/schemas/data.schema.json b/schemas/data.schema.json index 2d34661eed7..a75219bb06b 100644 --- a/schemas/data.schema.json +++ b/schemas/data.schema.json @@ -1,53 +1,124 @@ { - "$ref": "#/definitions/WebFeaturesData", - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "http://json-schema.org/draft-07/schema", + "description": "The top-level web-features data package", + "type": "object", + "properties": { + "browsers": { + "description": "Browsers and browser release data", + "type": "object", + "properties": { + "chrome": { + "$ref": "#/definitions/BrowserData" + }, + "chrome_android": { + "$ref": "#/definitions/BrowserData" + }, + "edge": { + "$ref": "#/definitions/BrowserData" + }, + "firefox": { + "$ref": "#/definitions/BrowserData" + }, + "firefox_android": { + "$ref": "#/definitions/BrowserData" + }, + "safari": { + "$ref": "#/definitions/BrowserData" + }, + "safari_ios": { + "$ref": "#/definitions/BrowserData" + } + }, + "required": [ + "chrome", + "chrome_android", + "edge", + "firefox", + "firefox_android", + "safari", + "safari_ios" + ], + "additionalProperties": false + }, + "features": { + "description": "Feature identifiers and data", + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/FeatureData" + }, + { + "$ref": "#/definitions/FeatureMovedData" + }, + { + "$ref": "#/definitions/FeatureSplitData" + } + ], + "$comment": "Use the `kind` property as a discriminator." + } + }, + "groups": { + "description": "Group identifiers and data", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/GroupData" + } + }, + "snapshots": { + "description": "Snapshot identifiers and data", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/SnapshotData" + } + } + }, + "required": ["browsers", "features", "groups"], + "additionalProperties": false, "definitions": { + "Discouraged": { + "type": "object", + "properties": { + "according_to": { + "description": "Links to a formal discouragement notice, such as specification text, intent-to-unship, etc.", + "$ref": "#/definitions/URLs" + }, + "alternatives": { + "description": "IDs for features that substitute some or all of this feature's utility", + "$ref": "#/definitions/Strings" + } + }, + "required": ["according_to"], + "additionalProperties": false + }, "BrowserData": { - "additionalProperties": false, "description": "Browser information", + "type": "object", "properties": { "name": { "description": "The name of the browser, as in \"Edge\" or \"Safari on iOS\"", "type": "string" }, "releases": { - "description": "The browser's releases", + "type": "array", "items": { "$ref": "#/definitions/Release" - }, - "type": "array" + } } }, - "required": [ - "name", - "releases" - ], - "type": "object" + "required": ["name", "releases"], + "additionalProperties": false }, "FeatureData": { - "additionalProperties": false, + "description": "A feature data entry", + "type": "object", "properties": { - "caniuse": { - "anyOf": [ - { - "type": "string" - }, - { - "items": { - "type": "string" - }, - "minItems": 2, - "type": "array" - } - ], - "description": "caniuse.com identifier(s)" + "kind": { + "const": "feature" }, - "compat_features": { - "description": "Sources of support data for this feature", - "items": { - "type": "string" - }, - "type": "array" + "name": { + "description": "Short name", + "type": "string" }, "description": { "description": "Short description of the feature, as a plain text string", @@ -57,212 +128,47 @@ "description": "Short description of the feature, as an HTML string", "type": "string" }, - "discouraged": { - "additionalProperties": false, - "description": "Whether developers are formally discouraged from using this feature", - "properties": { - "according_to": { - "description": "Links to a formal discouragement notice, such as specification text, intent-to-unship, etc.", - "items": { - "type": "string" - }, - "type": "array" - }, - "alternatives": { - "description": "IDs for features that substitute some or all of this feature's utility", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "according_to" - ], - "type": "object" + "spec": { + "description": "Specification URL(s)", + "$ref": "#/definitions/URLOrURLs" }, "group": { - "anyOf": [ - { - "type": "string" - }, - { - "items": { - "type": "string" - }, - "minItems": 2, - "type": "array" - } - ], - "description": "Group identifier(s)" - }, - "name": { - "description": "Short name", - "type": "string" + "description": "Group identifier(s)", + "$ref": "#/definitions/StringOrStrings" }, "snapshot": { - "anyOf": [ - { - "type": "string" - }, - { - "items": { - "type": "string" - }, - "minItems": 2, - "type": "array" - } - ], - "description": "Snapshot identifier(s)" + "description": "Snapshot identifier(s)", + "$ref": "#/definitions/StringOrStrings" }, - "spec": { - "anyOf": [ - { - "type": "string" - }, - { - "items": { - "type": "string" - }, - "minItems": 2, - "type": "array" - } - ], - "description": "Specification URL(s)" + "caniuse": { + "description": "caniuse.com identifier(s)", + "$ref": "#/definitions/StringOrStrings" + }, + "compat_features": { + "description": "Sources of support data for this feature", + "$ref": "#/definitions/Strings" }, "status": { - "additionalProperties": false, - "description": "Whether a feature is considered a \"baseline\" web platform feature and when it achieved that status", - "properties": { - "baseline": { - "description": "Whether the feature is Baseline (low substatus), Baseline (high substatus), or not (false)", - "enum": [ - "high", - "low", - false - ], - "type": [ - "string", - "boolean" - ] - }, - "baseline_high_date": { - "description": "Date the feature achieved Baseline high status", - "type": "string" - }, - "baseline_low_date": { - "description": "Date the feature achieved Baseline low status", - "type": "string" - }, - "by_compat_key": { - "additionalProperties": { - "additionalProperties": false, - "properties": { - "baseline": { - "description": "Whether the feature is Baseline (low substatus), Baseline (high substatus), or not (false)", - "enum": [ - "high", - "low", - false - ], - "type": [ - "string", - "boolean" - ] - }, - "baseline_high_date": { - "description": "Date the feature achieved Baseline high status", - "type": "string" - }, - "baseline_low_date": { - "description": "Date the feature achieved Baseline low status", - "type": "string" - }, - "support": { - "additionalProperties": false, - "description": "Browser versions that most-recently introduced the feature", - "properties": { - "chrome": { - "type": "string" - }, - "chrome_android": { - "type": "string" - }, - "edge": { - "type": "string" - }, - "firefox": { - "type": "string" - }, - "firefox_android": { - "type": "string" - }, - "safari": { - "type": "string" - }, - "safari_ios": { - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "baseline", - "support" - ], - "type": "object" - }, - "description": "Statuses for each key in the feature's compat_features list, if applicable. Not available to the npm release of web-features.", - "type": "object" - }, - "support": { - "additionalProperties": false, - "description": "Browser versions that most-recently introduced the feature", - "properties": { - "chrome": { - "type": "string" - }, - "chrome_android": { - "type": "string" - }, - "edge": { - "type": "string" - }, - "firefox": { - "type": "string" - }, - "firefox_android": { - "type": "string" - }, - "safari": { - "type": "string" - }, - "safari_ios": { - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "baseline", - "support" - ], - "type": "object" + "description": "Whether a feature is considered a \"Baseline\" web platform feature and when it achieved that status", + "$ref": "#/definitions/StatusHeadline" + }, + "discouraged": { + "description": "Whether developers are formally discouraged from using this feature", + "$ref": "#/definitions/Discouraged" } }, "required": [ + "kind", "name", "description", "description_html", "spec", "status" ], - "type": "object" + "additionalProperties": false }, "GroupData": { - "additionalProperties": false, + "type": "object", "properties": { "name": { "description": "Short name", @@ -273,117 +179,179 @@ "type": "string" } }, - "required": [ - "name" - ], - "type": "object" + "required": ["name"], + "additionalProperties": false }, "Release": { - "additionalProperties": false, "description": "Browser release information", + "type": "object", "properties": { - "date": { - "description": "The release date, as in \"2023-12-11\"", - "type": "string" - }, "version": { "description": "The version string, as in \"10\" or \"17.1\"", "type": "string" + }, + "date": { + "description": " The release date, as in \"2023-12-11\"", + "type": "string" } }, - "required": [ - "version", - "date" - ], - "type": "object" + "required": ["version", "date"], + "additionalProperties": false }, - "SnapshotData": { - "additionalProperties": false, + "FeatureMovedData": { + "description": "A feature has permanently moved to exactly one other ID", + "type": "object", "properties": { - "name": { - "description": "Short name", - "type": "string" + "kind": { + "const": "moved" }, - "spec": { - "description": "Specification", + "redirect_target": { + "description": "The new ID for this feature", "type": "string" } }, - "required": [ - "name", - "spec" - ], - "type": "object" + "required": ["kind", "redirect_target"], + "additionalProperties": false }, - "WebFeaturesData": { - "additionalProperties": false, + "FeatureSplitData": { + "description": "A feature has split into two or more other features", + "type": "object", "properties": { - "browsers": { - "additionalProperties": false, - "description": "Browsers and browser release data", + "kind": { + "const": "split" + }, + "redirect_targets": { + "description": "The new IDs for this feature", + "$ref": "#/definitions/Strings" + } + }, + "required": ["kind", "redirect_targets"], + "additionalProperties": false + }, + "Status": { + "type": "object", + "properties": { + "baseline": { + "description": "Whether the feature is Baseline (low substatus), Baseline (high substatus), or not (false)", + "enum": ["high", "low", false] + }, + "baseline_high_date": { + "description": "Date the feature achieved Baseline high status", + "type": "string" + }, + "baseline_low_date": { + "description": "Date the feature achieved Baseline low status", + "type": "string" + }, + "support": { + "description": "Browser versions that most-recently introduced the feature", + "type": "object", "properties": { "chrome": { - "$ref": "#/definitions/BrowserData" + "type": "string" }, "chrome_android": { - "$ref": "#/definitions/BrowserData" + "type": "string" }, "edge": { - "$ref": "#/definitions/BrowserData" + "type": "string" }, "firefox": { - "$ref": "#/definitions/BrowserData" + "type": "string" }, "firefox_android": { - "$ref": "#/definitions/BrowserData" + "type": "string" }, "safari": { - "$ref": "#/definitions/BrowserData" + "type": "string" }, "safari_ios": { - "$ref": "#/definitions/BrowserData" + "type": "string" } }, - "required": [ - "chrome", - "chrome_android", - "edge", - "firefox", - "firefox_android", - "safari", - "safari_ios" - ], - "type": "object" - }, - "features": { + "additionalProperties": false + } + }, + "required": ["baseline", "support"] + }, + "StatusHeadline": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/Status" }], + "properties": { + "baseline": {}, + "baseline_high_date": {}, + "baseline_low_date": {}, + "support": {}, + "by_compat_key": { + "description": "Statuses for each key in the feature's compat_features list, if applicable. Not available to the npm release of web-features.", + "type": "object", "additionalProperties": { - "$ref": "#/definitions/FeatureData" - }, - "description": "Feature identifiers and data", - "type": "object" + "$ref": "#/definitions/Status" + } + } + }, + "required": ["baseline", "support"], + "additionalProperties": false + }, + "SnapshotData": { + "type": "object", + "properties": { + "name": { + "description": "Short name", + "type": "string" }, - "groups": { - "additionalProperties": { - "$ref": "#/definitions/GroupData" - }, - "description": "Group identifiers and data", - "type": "object" + "spec": { + "description": "Specification", + "$ref": "#/definitions/URL" + } + }, + "required": ["name", "spec"], + "additionalProperties": false + }, + "StringOrStrings": { + "oneOf": [ + { + "type": "string" }, - "snapshots": { - "additionalProperties": { - "$ref": "#/definitions/SnapshotData" + { + "type": "array", + "items": { + "type": "string" }, - "description": "Snapshot identifiers and data", - "type": "object" + "minItems": 2 } + ] + }, + "Strings": { + "type": "array", + "items": { + "type": "string" }, - "required": [ - "browsers", - "features", - "groups", - "snapshots" - ], - "type": "object" + "minItems": 1 + }, + "URL": { + "type": "string" + }, + "URLs": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "URLOrURLs": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 2 + } + ] } } -} \ No newline at end of file +} diff --git a/scripts/build.ts b/scripts/build.ts index 35f346481ce..04c4aa2a14e 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -7,6 +7,7 @@ import { basename } from "node:path"; import winston from "winston"; import yargs from "yargs"; import * as data from "../index.js"; +import { isOrdinaryFeatureData } from "../type-guards.js"; import { validate } from "./validate.js"; const logger = winston.createLogger({ @@ -35,7 +36,12 @@ yargs(process.argv.slice(2)) function buildPackage() { const packageDir = new URL("./packages/web-features/", rootDir); - const filesToCopy = ["LICENSE.txt", "types.ts", "schemas/data.schema.json"]; + const filesToCopy = [ + "LICENSE.txt", + "types.quicktype.ts", + "types.ts", + "schemas/data.schema.json", + ]; if (!valid(data)) { logger.error("Data failed schema validation. No package built."); @@ -63,6 +69,10 @@ function buildPackage() { function buildExtendedJSON() { for (const [id, featureData] of Object.entries(data.features)) { + if (!isOrdinaryFeatureData(featureData)) { + continue; + } + if ( Array.isArray(featureData.compat_features) && featureData.compat_features.length && diff --git a/scripts/dist.ts b/scripts/dist.ts index 209aa1d154a..1832f6a4b89 100644 --- a/scripts/dist.ts +++ b/scripts/dist.ts @@ -14,6 +14,7 @@ import { isDeepStrictEqual } from "node:util"; import winston from "winston"; import YAML, { Document, Scalar, YAMLSeq } from "yaml"; import yargs from "yargs"; +import type { FeatureData, FeatureMovedData, FeatureSplitData } from "../types"; const compat = new Compat(); @@ -181,6 +182,39 @@ function compareStatus(a: SupportStatus, b: SupportStatus) { return 0; } +function toRedirectDist( + id: string, + source: FeatureMovedData | FeatureSplitData, +): YAML.Document { + const dist = new Document({}); + + const comment = [ + `Generated from: ${id}.yml`, + `This file intentionally left blank.`, + `Do not edit this file.`, + ]; + + const { kind } = source; + switch (kind) { + case "moved": + comment.push( + `The data for this feature has moved to ${source.redirect_target}.yml`, + ); + break; + case "split": + comment.push(`The data for this feature has moved to:`); + comment.push(...source.redirect_targets.map((dest) => ` - ${dest}.yml`)); + break; + default: + kind satisfies never; + throw new Error(`Unhandled feature kind ${kind}}`); + } + + dist.commentBefore = comment.map((line) => ` ${line}`).join("\n"); + + return dist; +} + /** * Generate a dist YAML document from a feature definition YAML file path. * @@ -192,6 +226,11 @@ function toDist(sourcePath: string): YAML.Document { const source = YAML.parse(fs.readFileSync(sourcePath, { encoding: "utf-8" })); const { name: id } = path.parse(sourcePath); + if ("redirect_target" in source || "redirect_targets" in source) { + return toRedirectDist(id, source); + } + source as Partial; + // Collect tagged compat features. A `compat_features` list in the source // takes precedence, but can be removed if it matches the tagged features. const taggedCompatFeatures = (tagsToFeatures.get(`web-features:${id}`) ?? []) diff --git a/scripts/find-ranged-headline-statuses.ts b/scripts/find-ranged-headline-statuses.ts index a5dabd2f0cd..e60f21efd00 100644 --- a/scripts/find-ranged-headline-statuses.ts +++ b/scripts/find-ranged-headline-statuses.ts @@ -1,7 +1,13 @@ import { features } from "../index"; +import { isOrdinaryFeatureData } from "../type-guards"; for (const [key, data] of Object.entries(features)) { - if ((data.status.baseline_low_date ?? "").includes("≤")) { - console.log(key); + if (isOrdinaryFeatureData(data)) { + if ( + "status" in data && + (data.status.baseline_low_date ?? "").includes("≤") + ) { + console.log(key); + } } } diff --git a/scripts/schema.ts b/scripts/schema.ts index 357bcf85a21..24cc429c0b3 100644 --- a/scripts/schema.ts +++ b/scripts/schema.ts @@ -9,15 +9,15 @@ import { validate } from "./validate.js"; let status: 0 | 1 = 0; -function checkSchemaConsistency(): void { - const schemaPath: string = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "../schemas/data.schema.json"); - const schemaOnDisk: string = fs.readFileSync(schemaPath, { encoding: "utf-8"}); - const schemaGenerated: string = child_process.execSync("npm run --silent schema", { encoding: "utf-8"}).trim(); +function checkGeneratedFileConsistency(): void { + const quicktypePath: string = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "../types.quicktype.ts"); + const quicktypeOnDisk: string = fs.readFileSync(quicktypePath, { encoding: "utf-8"}); + const quicktypeGenerated: string = child_process.execSync("npm run --silent schematypes", { encoding: "utf-8"}); - if (schemaOnDisk !== schemaGenerated) { - console.error("There's a mismatch between the schema on disk and types in `index.ts`."); + if (quicktypeOnDisk !== quicktypeGenerated) { + console.error("There's a mismatch between the types generated by quicktype and the types in `types.quicktype.ts`."); console.error("This may produce misleading results for feature validation."); - console.error("To fix this, run `npm run schema:write`."); + console.error("To fix this, run `npm run schematypes:write`."); status = 1; } } @@ -35,6 +35,6 @@ function valid() { } } -checkSchemaConsistency(); +checkGeneratedFileConsistency(); valid(); process.exit(status); diff --git a/scripts/specs.ts b/scripts/specs.ts index 7978e6e0069..c597d21761b 100644 --- a/scripts/specs.ts +++ b/scripts/specs.ts @@ -3,6 +3,7 @@ import assert from "node:assert/strict"; import webSpecs from 'web-specs' with { type: 'json' }; import { features } from '../index.js'; +import { isOrdinaryFeatureData } from "../type-guards.js"; // Specs needs to be in "good standing". Nightly URLs are used if available, // otherwise the snapshot/versioned URL is used. See browser-specs/web-specs @@ -191,6 +192,10 @@ for (const [allowedUrl, message] of defaultAllowlist) { } for (const [id, data] of Object.entries(features)) { + if (!isOrdinaryFeatureData(data)) { + continue; + } + const specs = Array.isArray(data.spec) ? data.spec : [data.spec]; for (const spec of specs) { let url: URL; diff --git a/scripts/stats.ts b/scripts/stats.ts index 1894c73ba96..404efe51ddf 100644 --- a/scripts/stats.ts +++ b/scripts/stats.ts @@ -2,6 +2,7 @@ import { Compat } from "compute-baseline/browser-compat-data"; import { fileURLToPath } from "node:url"; import yargs from "yargs"; import { features } from "../index.js"; +import { isOrdinaryFeatureData } from "../type-guards.js"; const argv = yargs(process.argv.slice(2)) .scriptName("stats") @@ -14,11 +15,20 @@ const argv = yargs(process.argv.slice(2)) }).argv; export function stats(detailed: boolean = false) { - const featureCount = Object.keys(features).length; + const featureCount = Object.values(features).filter( + isOrdinaryFeatureData, + ).length; const keys = []; const doneKeys = Array.from( - new Set(Object.values(features).flatMap((f) => f.compat_features ?? [])), + new Set( + Object.values(features).flatMap((f) => { + if (isOrdinaryFeatureData(f)) { + return f.compat_features ?? []; + } + return []; + }), + ), ); const toDoKeys = []; @@ -35,6 +45,7 @@ export function stats(detailed: boolean = false) { } const featureSizes = Object.values(features) + .filter(isOrdinaryFeatureData) .map((feature) => (feature.compat_features ?? []).length) .sort((a, b) => a - b); diff --git a/scripts/update-drafts.ts b/scripts/update-drafts.ts index f3fac0babdf..ab84d708596 100644 --- a/scripts/update-drafts.ts +++ b/scripts/update-drafts.ts @@ -11,6 +11,7 @@ import { Document, parse } from "yaml"; import yargs from "yargs"; import { features } from "../index.js"; +import { isOrdinaryFeatureData } from "../type-guards.js"; import { FeatureData } from "../types.js"; type WebSpecsSpec = (typeof webSpecs)[number]; @@ -84,7 +85,7 @@ async function main() { // Build a map of used BCD keys to feature. const webFeatures = new Map(); Object.values(features).map((data) => { - if (data.compat_features) { + if (isOrdinaryFeatureData(data) && data.compat_features) { for (const compatFeature of data.compat_features) { webFeatures.set(compatFeature, data.name); } @@ -261,9 +262,12 @@ async function main() { } // Clean up completed specs, even if they've been superseded - const assignedKeys = Object.values(features).flatMap( - (f) => f.compat_features ?? [], - ); + const assignedKeys = Object.values(features).flatMap((f) => { + if (isOrdinaryFeatureData(f)) { + return f.compat_features ?? []; + } + return []; + }); for (const spec of webSpecs) { const id = formatIdentifier(spec.shortname); const destination = `features/draft/spec/${id}.yml`; diff --git a/type-guards.ts b/type-guards.ts new file mode 100644 index 00000000000..806a88139d4 --- /dev/null +++ b/type-guards.ts @@ -0,0 +1,13 @@ +import type { FeatureData, FeatureMovedData, FeatureSplitData } from "./types"; + +export function isOrdinaryFeatureData(x: unknown): x is FeatureData { + return typeof x === "object" && "kind" in x && x.kind === "feature"; +} + +export function isSplit(x: unknown): x is FeatureSplitData { + return typeof x === "object" && "kind" in x && x.kind === "split"; +} + +export function isMoved(x: unknown): x is FeatureMovedData { + return typeof x === "object" && "kind" in x && x.kind === "moved"; +} diff --git a/types.quicktype.ts b/types.quicktype.ts new file mode 100644 index 00000000000..f76a24fabef --- /dev/null +++ b/types.quicktype.ts @@ -0,0 +1,221 @@ +/** + * The top-level web-features data package + */ +export interface WebFeaturesData { + /** + * Browsers and browser release data + */ + browsers: Browsers; + /** + * Feature identifiers and data + */ + features: { [key: string]: FeatureData }; + /** + * Group identifiers and data + */ + groups: { [key: string]: GroupData }; + /** + * Snapshot identifiers and data + */ + snapshots?: { [key: string]: SnapshotData }; +} + +/** + * Browsers and browser release data + */ +export interface Browsers { + chrome: BrowserData; + chrome_android: BrowserData; + edge: BrowserData; + firefox: BrowserData; + firefox_android: BrowserData; + safari: BrowserData; + safari_ios: BrowserData; +} + +/** + * Browser information + */ +export interface BrowserData { + /** + * The name of the browser, as in "Edge" or "Safari on iOS" + */ + name: string; + releases: Release[]; +} + +/** + * Browser release information + */ +export interface Release { + /** + * The release date, as in "2023-12-11" + */ + date: string; + /** + * The version string, as in "10" or "17.1" + */ + version: string; +} + +/** + * A feature data entry + * + * A feature has permanently moved to exactly one other ID + * + * A feature has split into two or more other features + */ +export interface FeatureData { + /** + * caniuse.com identifier(s) + */ + caniuse?: string[] | string; + /** + * Sources of support data for this feature + */ + compat_features?: string[]; + /** + * Short description of the feature, as a plain text string + */ + description?: string; + /** + * Short description of the feature, as an HTML string + */ + description_html?: string; + /** + * Whether developers are formally discouraged from using this feature + */ + discouraged?: Discouraged; + /** + * Group identifier(s) + */ + group?: string[] | string; + kind: Kind; + /** + * Short name + */ + name?: string; + /** + * Snapshot identifier(s) + */ + snapshot?: string[] | string; + /** + * Specification URL(s) + */ + spec?: string[] | string; + /** + * Whether a feature is considered a "Baseline" web platform feature and when it achieved + * that status + */ + status?: StatusHeadline; + /** + * The new ID for this feature + */ + redirect_target?: string; + /** + * The new IDs for this feature + */ + redirect_targets?: string[]; +} + +/** + * Whether developers are formally discouraged from using this feature + */ +export interface Discouraged { + /** + * Links to a formal discouragement notice, such as specification text, intent-to-unship, + * etc. + */ + according_to: string[]; + /** + * IDs for features that substitute some or all of this feature's utility + */ + alternatives?: string[]; +} + +export type Kind = "feature" | "moved" | "split"; + +/** + * Whether a feature is considered a "Baseline" web platform feature and when it achieved + * that status + */ +export interface StatusHeadline { + /** + * Whether the feature is Baseline (low substatus), Baseline (high substatus), or not (false) + */ + baseline: boolean | BaselineEnum; + /** + * Date the feature achieved Baseline high status + */ + baseline_high_date?: string; + /** + * Date the feature achieved Baseline low status + */ + baseline_low_date?: string; + /** + * Statuses for each key in the feature's compat_features list, if applicable. Not available + * to the npm release of web-features. + */ + by_compat_key?: { [key: string]: Status }; + /** + * Browser versions that most-recently introduced the feature + */ + support: Support; +} + +export type BaselineEnum = "high" | "low"; + +export interface Status { + /** + * Whether the feature is Baseline (low substatus), Baseline (high substatus), or not (false) + */ + baseline: boolean | BaselineEnum; + /** + * Date the feature achieved Baseline high status + */ + baseline_high_date?: string; + /** + * Date the feature achieved Baseline low status + */ + baseline_low_date?: string; + /** + * Browser versions that most-recently introduced the feature + */ + support: Support; + [property: string]: any; +} + +/** + * Browser versions that most-recently introduced the feature + */ +export interface Support { + chrome?: string; + chrome_android?: string; + edge?: string; + firefox?: string; + firefox_android?: string; + safari?: string; + safari_ios?: string; +} + +export interface GroupData { + /** + * Short name + */ + name: string; + /** + * Identifier of parent group + */ + parent?: string; +} + +export interface SnapshotData { + /** + * Short name + */ + name: string; + /** + * Specification + */ + spec: string; +} diff --git a/types.ts b/types.ts index d1492262104..273bb0ac37d 100644 --- a/types.ts +++ b/types.ts @@ -1,97 +1,95 @@ -export interface WebFeaturesData { - /** Browsers and browser release data */ - browsers: { [key in BrowserIdentifier]: BrowserData }; - /** Feature identifiers and data */ - features: { [key: string]: FeatureData }; - /** Group identifiers and data */ - groups: { [key: string]: GroupData }; - /** Snapshot identifiers and data */ - snapshots: { [key: string]: SnapshotData }; -} - +// Quicktype produces a definitions that are correct, but not as narrow or +// well-named as hand-written type definition might produce. This module takes +// the Quicktype-generated types as renames or modifies the types to be somewhat +// nicer to work with in TypeScript. -/** Browser information */ -export interface BrowserData { - /** The name of the browser, as in "Edge" or "Safari on iOS" */ - name: string; - /** The browser's releases */ - releases: Release[]; -} +import type { + BaselineEnum as BaselineHighLow, + BrowserData, + Browsers, + Discouraged, + GroupData, + Kind, + FeatureData as QuicktypeMonolithicFeatureData, + WebFeaturesData as QuicktypeWebFeaturesData, + Release, + SnapshotData, + Status, + Support, + StatusHeadline as SupportStatus, +} from "./types.quicktype"; -/** Browser release information */ -export interface Release { - /** The version string, as in "10" or "17.1" */ - version: string; - /** The release date, as in "2023-12-11" */ - date: string; -} +// Passthrough types +export type { + BaselineHighLow, + BrowserData, + Browsers, + Discouraged, + GroupData, + Release, + SnapshotData, + Status, + Support, + SupportStatus, +}; -export interface FeatureData { - /** Short name */ - name: string; - /** Short description of the feature, as a plain text string */ - description: string; - /** Short description of the feature, as an HTML string */ - description_html: string; - /** Specification URL(s) */ - spec: string | [string, string, ...string[]]; - /** Group identifier(s) */ - group?: string | [string, string, ...string[]]; - /** Snapshot identifier(s) */ - snapshot?: string | [string, string, ...string[]]; - /** caniuse.com identifier(s) */ - caniuse?: string | [string, string, ...string[]]; - /** Whether a feature is considered a "baseline" web platform feature and when it achieved that status */ - status: SupportStatus; - /** Sources of support data for this feature */ - compat_features?: string[]; - /** Whether developers are formally discouraged from using this feature */ - discouraged?: Discouraged; +export interface WebFeaturesData + extends Pick { + features: { + [key: string]: FeatureData | FeatureMovedData | FeatureSplitData; + }; } -type BrowserIdentifier = "chrome" | "chrome_android" | "edge" | "firefox" | "firefox_android" | "safari" | "safari_ios"; +export type FeatureData = { kind: "feature" } & Required< + Pick< + QuicktypeMonolithicFeatureData, + "kind" | "description_html" | "description" | "name" | "spec" | "status" + > +> & + Partial< + Pick< + QuicktypeMonolithicFeatureData, + "caniuse" | "compat_features" | "discouraged" + > + >; -type BaselineHighLow = "high" | "low"; +export type FeatureRedirectData = { kind: Exclude } & Required< + Pick +>; -interface Status { - /** Whether the feature is Baseline (low substatus), Baseline (high substatus), or not (false) */ - baseline: BaselineHighLow | false; - /** Date the feature achieved Baseline low status */ - baseline_low_date?: string; - /** Date the feature achieved Baseline high status */ - baseline_high_date?: string; - /** Browser versions that most-recently introduced the feature */ - support: { - [K in BrowserIdentifier]?: string; - }; +export interface FeatureMovedData + extends Omit { + kind: "moved"; } -interface SupportStatus extends Status { - /** Statuses for each key in the feature's compat_features list, if applicable. Not available to the npm release of web-features. */ - by_compat_key?: Record +export interface FeatureSplitData + extends Omit { + kind: "split"; } -interface Discouraged { - /** Links to a formal discouragement notice, such as specification text, intent-to-unship, etc. */ - according_to: string[]; - /** IDs for features that substitute some or all of this feature's utility */ - alternatives?: string[]; - // TODO: alternatives ought to be `(keyof WebFeaturesData["features"])[]` - // but ts-json-schema-generator seems to have long-standing unresolved bugs - // around this. Remove this when - // https://github.com/web-platform-dx/web-features/issues/2722 is resolved. -} +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const t1: FeatureData = { + kind: "feature", + name: "Test", + description: "Hi", + description_html: "Hi", + spec: "", + status: { + baseline: false, + support: {}, + }, +}; -export interface GroupData { - /** Short name */ - name: string; - /** Identifier of parent group */ - parent?: string; -} +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const t2: FeatureMovedData = { + kind: "moved", + redirect_target: "", +}; -export interface SnapshotData { - /** Short name */ - name: string; - /** Specification */ - spec: string; -} +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const t3: FeatureSplitData = { + kind: "split", + redirect_targets: ["", ""], +}; + +export type BrowserIdentifier = keyof Browsers;